summaryrefslogtreecommitdiffhomepage
path: root/StarsEx/Water.cpp
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-04-01 21:23:39 +0200
committerAki <please@ignore.pl>2022-04-01 21:23:39 +0200
commit3c487c5cd69c53d6fea948643c0a76df03516605 (patch)
tree72730c7b8b26a5ef8fc9a987ec4c16129efd5aac /StarsEx/Water.cpp
parent8f353abd0bfe18baddd8a8250ab7c4f2d1c83a6e (diff)
downloadstarshatter-3c487c5cd69c53d6fea948643c0a76df03516605.zip
starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.gz
starshatter-3c487c5cd69c53d6fea948643c0a76df03516605.tar.bz2
Moved Stars45 to StarsEx
Diffstat (limited to 'StarsEx/Water.cpp')
-rw-r--r--StarsEx/Water.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/StarsEx/Water.cpp b/StarsEx/Water.cpp
new file mode 100644
index 0000000..5509938
--- /dev/null
+++ b/StarsEx/Water.cpp
@@ -0,0 +1,293 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Water surface effect w/ reflection and caustics
+*/
+
+#include "Water.h"
+#include "Random.h"
+
+// +--------------------------------------------------------------------+
+
+struct WATER_REFRACT
+{
+ // Vrefract = (V + refract * N) * norm
+ float refract;
+ float refractNorm;
+ DWORD diffuse;
+};
+
+struct WATER_SURFACE
+{
+ float height;
+ Vec3 normal;
+};
+
+// +--------------------------------------------------------------------+
+
+#if defined(_X86) && !defined(_WIN64)
+inline int f2i(float flt)
+{
+ volatile int n;
+
+ __asm
+ {
+ fld flt
+ fistp n
+ }
+
+ return n;
+}
+#else
+inline int f2i(float flt)
+{
+ return (int) flt;
+}
+#endif
+
+
+// +--------------------------------------------------------------------+
+
+static WATER_REFRACT RefractionTable[512];
+static bool refractInit = false;
+
+static const int WAVE_SIZE = 256;
+static const DWORD WAVE_MASK = 0xff;
+
+// +--------------------------------------------------------------------+
+
+Water::Water()
+: size(0), depth(0), scaleTex(1), avgHeight(0),
+nVertices(0), surface(0), waves(0)
+{
+}
+
+Water::~Water()
+{
+ delete [] surface;
+ delete [] waves;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+Water::Init(int n, float s, float d)
+{
+ size = s;
+ depth = d;
+ scaleTex = 1/size;
+
+ // Calculate number of vertices
+ nVertices = n;
+
+ // Create refraction table
+ if (!refractInit) {
+ WATER_REFRACT* refract = &RefractionTable[256];
+
+ for (UINT u = 0; u < 256; u++) {
+ float fCos0 = (float) u / (float) 256.0f;
+ float f0 = acosf(fCos0);
+ float fSin0 = sinf(f0);
+
+ float fSin1 = fSin0 / 1.333f; // water
+ float f1 = asinf(fSin1);
+ float fCos1 = cosf(f1);
+
+ refract[u].refract = fSin0 / fSin1 * fCos1 - fCos0;
+ refract[u].refractNorm = - fSin1 / fSin0;
+ refract[u].diffuse = ((((0xff - u)*(0xff - u)*(0xff - u)) << 8) & 0xff000000);
+
+ RefractionTable[u] = RefractionTable[256];
+ }
+
+ refractInit = true;
+ }
+
+ // Create maps
+ if (surface)
+ delete [] surface;
+
+ surface = new WATER_SURFACE[n*n];
+ ZeroMemory(surface, n*n * sizeof(WATER_SURFACE));
+
+ if (waves)
+ delete [] waves;
+
+ waves = new float[WAVE_SIZE*4];
+
+ double f = 1.0 / (double) WAVE_SIZE;
+ for (int i = 0; i < WAVE_SIZE; i++) {
+ double s0 = sin(2*PI*i*f);
+ double s1 = sin(4*PI*i*f);
+ double s2 = sin(6*PI*i*f);
+ double s3 = sin(8*PI*i*f);
+
+ waves[0*WAVE_SIZE + i] = (float) (1.8 * s0*s0 - 0.9);
+ waves[1*WAVE_SIZE + i] = (float) (1.6 * s1*s1 - 0.8);
+ waves[2*WAVE_SIZE + i] = (float) (0.4 * s2);
+ waves[3*WAVE_SIZE + i] = (float) (0.8 * s3*s3 - 0.4);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ offsets[i] = (float) Random(0, WAVE_SIZE);
+ }
+
+ offsets[4] = 12.45f;
+ offsets[5] = 14.23f;
+ offsets[6] = 16.72f;
+ offsets[7] = 20.31f;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+Water::CalcWaves(double seconds)
+{
+ int i, n[4];
+ UINT SIZE = nVertices;
+ UINT STEP = WAVE_SIZE / (SIZE-1);
+ UINT STEP2 = STEP/2;
+ UINT AREA = SIZE * SIZE;
+ UINT x, y;
+
+ for (i = 0; i < 4; i++) {
+ n[i] = (int) offsets[i];
+ }
+
+ WATER_SURFACE* pSurf = surface;
+
+ // compute heights
+ for (y = 0; y < SIZE; y++) {
+ for (x = 0; x < SIZE; x++) {
+ float h = 0;
+ h += waves[ ((n[0] + x*STEP
+ - y*STEP2) & WAVE_MASK) + 0*WAVE_SIZE ];
+ h += waves[ ((n[1] + x*STEP2
+ + y*STEP) & WAVE_MASK) + 1*WAVE_SIZE ];
+ h += waves[ ((n[2] + x*STEP) & WAVE_MASK) + 2*WAVE_SIZE ];
+ h += waves[ ((n[3] + y*STEP) & WAVE_MASK) + 3*WAVE_SIZE ];
+
+ pSurf->height = h * depth;
+ pSurf++;
+ }
+ }
+
+ // compute normals
+ UINT uXN, uX0, uXP;
+ UINT uYN, uY0, uYP;
+
+ uYP = AREA - SIZE;
+ uY0 = 0;
+ uYN = SIZE;
+
+ for (y = 0; y < SIZE; y++) {
+ uXP = SIZE - 1;
+ uX0 = 0;
+ uXN = 1;
+
+ for (x = 0; x < SIZE; x++) {
+ Vec3 vecN;
+ float f;
+
+ f = surface[uXN + uYN].height - surface[uXP + uYP].height; vecN.x = vecN.z = f;
+ f = surface[uX0 + uYN].height - surface[uX0 + uYP].height; vecN.z += f;
+ f = surface[uXP + uYN].height - surface[uXN + uYP].height; vecN.x -= f; vecN.z += f;
+ f = surface[uXN + uY0].height - surface[uXP + uY0].height; vecN.x += f;
+
+ vecN.y = -15.0f * depth;
+ vecN.Normalize();
+
+ surface[uX0 + uY0].normal = vecN * -1.0f;
+
+ uXP = uX0;
+ uX0 = uXN;
+ uXN = (uXN + 1) % SIZE;
+ }
+
+ uYP = uY0;
+ uY0 = uYN;
+ uYN = (uYN + SIZE) % AREA;
+ }
+
+ // update offsets
+ for (i = 0; i < 4; i++) {
+ offsets[i] += (float) (offsets[i+4] * seconds);
+
+ if (offsets[i] > WAVE_SIZE)
+ offsets[i] -= WAVE_SIZE;
+ }
+
+}
+
+// +--------------------------------------------------------------------+
+
+void
+Water::UpdateSurface(Vec3& eyePos, VertexSet* vset)
+{
+ UINT SIZE = nVertices;
+ UINT AREA = SIZE * SIZE;
+ UINT x, y;
+
+ WATER_SURFACE* pSurf = surface;
+ Vec3* pLoc = vset->loc;
+ Vec3* pNorm = vset->nrm;
+ DWORD* pDiff = vset->diffuse;
+ float* pTu = vset->tu;
+ float* pTv = vset->tv;
+
+ float fInc = 1.0f / (float) (SIZE-1);
+ float fx = 0.0f;
+ float fz = 0.0f;
+
+ for (y = 0; y < SIZE; y++) {
+ for (x = 0; x < SIZE; x++) {
+ // update vertex height and normal
+ pLoc->y += pSurf->height;
+ *pNorm = pSurf->normal;
+
+ /*
+ // Update texture coords and diffuse based upon refraction
+ Vec3 vec = eyePos - *pLoc;
+ vec.Normalize();
+
+ WATER_REFRACT *pRefract;
+ pRefract = RefractionTable + 256 + f2i(vec.dot(*pNorm) * 255.0f);
+
+ *pDiff = pRefract->diffuse;
+
+ // compute apparent displacement
+ Vec3 vecD = (pSurf->normal * pRefract->refract + vec) * pRefract->refractNorm;
+ Vec3 vecP = *pLoc;
+ vecP.y -= depth;
+
+ // perturb texture coords
+ float fB = vecD * vecP * 2.0f;
+ float fD = fB * fB - depth;
+ float fScale = (-fB + sqrtf(fD)) * 0.5f;
+
+ *pTu = vecD.x * fScale + fx;
+ *pTv = vecD.z * fScale + fz;
+ */
+
+ fx += fInc;
+ pSurf++;
+ pLoc++;
+ pNorm++;
+ pDiff++;
+ pTu++;
+ pTv++;
+ }
+
+ fx = 0.0f;
+ fz += fInc;
+ }
+}
+
+