summaryrefslogtreecommitdiff
path: root/indra/newview/llvowater.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvowater.cpp')
-rw-r--r--indra/newview/llvowater.cpp1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
new file mode 100644
index 0000000000..135873b5b8
--- /dev/null
+++ b/indra/newview/llvowater.cpp
@@ -0,0 +1,1028 @@
+/**
+ * @file llvowater.cpp
+ * @brief LLVOWater class implementation
+ *
+ * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvowater.h"
+
+#include "imageids.h"
+#include "llviewercontrol.h"
+
+#include "llagent.h"
+#include "lldrawable.h"
+#include "lldrawpoolwater.h"
+#include "llface.h"
+#include "llsky.h"
+#include "llsurface.h"
+#include "llvosky.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+#include "pipeline.h"
+
+const BOOL gUseRoam = FALSE;
+
+
+///////////////////////////////////
+
+#include "randgauss.h"
+
+template<class T> inline T LERP(T a, T b, F32 factor)
+{
+ return a + (b - a) * factor;
+}
+
+const U32 N_RES_HALF = (N_RES >> 1);
+
+const U32 WIDTH = (N_RES * WAVE_STEP); //128.f //64 // width of wave tile, in meters
+const F32 WAVE_STEP_INV = (1. / WAVE_STEP);
+
+const F32 g = 9.81f; // gravitational constant (m/s^2)
+
+///////////////////////////////////
+
+LLWaterSurface::LLWaterSurface() :
+ mInitialized(FALSE),
+ mWind(9, 0, 0),
+ mA(0.2f),
+ mVisc(0.001f),
+ mShininess(8.0f)
+{}
+
+
+LLWaterGrid *LLVOWater::sGrid = 0;
+
+
+LLVOWater::LLVOWater(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+: LLViewerObject(id, LL_VO_WATER, regionp)
+{
+ // Terrain must draw during selection passes so it can block objects behind it.
+ mbCanSelect = FALSE;
+ setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility.
+
+ mUseTexture = TRUE;
+}
+
+
+void LLVOWater::markDead()
+{
+ LLViewerObject::markDead();
+}
+
+
+BOOL LLVOWater::isActive() const
+{
+ return FALSE;
+}
+
+
+void LLVOWater::setPixelAreaAndAngle(LLAgent &agent)
+{
+ mAppAngle = 50;
+ mPixelArea = 500*500;
+}
+
+
+// virtual
+void LLVOWater::updateTextures(LLAgent &agent)
+{
+}
+
+// virtual
+void LLVOWater::updateDrawable(BOOL force_damped)
+{
+ // Force an immediate rebuild on any update
+ if (mDrawable.notNull())
+ {
+ gPipeline.updateMoveNormalAsync(mDrawable);
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+ }
+ clearChanged(SHIFTED);
+}
+
+// Never gets called
+BOOL LLVOWater::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+ if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER)))
+ {
+ return TRUE;
+ }
+ if (mDrawable)
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+ }
+ return TRUE;
+}
+
+LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+ mDrawable->setLit(FALSE);
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_WATER);
+
+ LLDrawPoolWater *pool = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER);
+
+ if (mUseTexture)
+ {
+ mDrawable->setNumFaces(1, pool, mRegionp->getLand().getWaterTexture());
+ }
+ else
+ {
+ mDrawable->setNumFaces(1, pool, gWorldp->getDefaultWaterTexture());
+ }
+
+ return mDrawable;
+}
+
+BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
+{
+ return updateGeometryFlat(drawable);
+}
+
+
+BOOL LLVOWater::updateGeometryFlat(LLDrawable *drawable)
+{
+ LLFace *face;
+
+ if (drawable->getNumFaces() < 1)
+ {
+ drawable->addFace(gPipeline.getPool(LLDrawPool::POOL_WATER), NULL);
+ }
+ face = drawable->getFace(0);
+
+ LLVector2 uvs[4];
+ LLVector3 vtx[4];
+
+ LLStrider<LLVector3> verticesp, normalsp;
+ LLStrider<LLVector2> texCoordsp;
+ U32 *indicesp;
+ S32 index_offset;
+
+ S32 size = 16;
+
+ S32 num_quads = size*size;
+
+ face->setPrimType(LLTriangles);
+ face->setSize(4*num_quads, 6*num_quads);
+ index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
+ if (-1 == index_offset)
+ {
+ return TRUE;
+ }
+
+ LLVector3 position_agent;
+ position_agent = getPositionAgent();
+ face->mCenterAgent = position_agent;
+
+ S32 x, y;
+ F32 step_x = getScale().mV[0] / size;
+ F32 step_y = getScale().mV[1] / size;
+
+ const LLVector3 up(0.f, step_y * 0.5f, 0.f);
+ const LLVector3 right(step_x * 0.5f, 0.f, 0.f);
+ const LLVector3 normal(0.f, 0.f, 1.f);
+
+ F32 size_inv = 1.f / size;
+
+ for (y = 0; y < size; y++)
+ {
+ for (x = 0; x < size; x++)
+ {
+ S32 toffset = index_offset + 4*(y*size + x);
+ position_agent = getPositionAgent() - getScale() * 0.5f;
+ position_agent.mV[VX] += (x + 0.5f) * step_x;
+ position_agent.mV[VY] += (y + 0.5f) * step_y;
+
+ vtx[0] = position_agent - right + up;
+ vtx[1] = position_agent - right - up;
+ vtx[2] = position_agent + right + up;
+ vtx[3] = position_agent + right - up;
+
+ *(verticesp++) = vtx[0];
+ *(verticesp++) = vtx[1];
+ *(verticesp++) = vtx[2];
+ *(verticesp++) = vtx[3];
+
+ uvs[0].setVec(x*size_inv, (y+1)*size_inv);
+ uvs[1].setVec(x*size_inv, y*size_inv);
+ uvs[2].setVec((x+1)*size_inv, (y+1)*size_inv);
+ uvs[3].setVec((x+1)*size_inv, y*size_inv);
+
+ *(texCoordsp) = uvs[0];
+ texCoordsp++;
+ *(texCoordsp) = uvs[1];
+ texCoordsp++;
+ *(texCoordsp) = uvs[2];
+ texCoordsp++;
+ *(texCoordsp) = uvs[3];
+ texCoordsp++;
+
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+ *(normalsp++) = normal;
+
+ *indicesp++ = toffset + 0;
+ *indicesp++ = toffset + 1;
+ *indicesp++ = toffset + 2;
+
+ *indicesp++ = toffset + 1;
+ *indicesp++ = toffset + 3;
+ *indicesp++ = toffset + 2;
+ }
+ }
+
+
+ mDrawable->movePartition();
+ LLPipeline::sCompiles++;
+ return TRUE;
+}
+
+
+BOOL LLVOWater::updateGeometryHeightFieldRoam(LLDrawable *drawable)
+{
+ LLVector3 position_agent = getPositionAgent();
+ const LLVector3 region_size = getScale();
+ const LLVector3 region_origin = position_agent - region_size * 0.5f;
+
+ S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth;
+ S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth;
+ S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth;
+ S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth;
+
+ static S32 res = (S32)sGrid->mPatchRes;
+ if (patch_origx < 0)
+ {
+ patch_dimx -= - patch_origx;
+ if (patch_dimx < 1)
+ {
+ return TRUE;
+ }
+ patch_origx = 0;
+ }
+ if (patch_origy < 0)
+ {
+ patch_dimy -= - patch_origy;
+ if (patch_dimy < 1)
+ {
+ return TRUE;
+ }
+ patch_origy = 0;
+ }
+ if (patch_origx >= res)
+ {
+ return TRUE;
+ }
+ if (patch_origy >= res)
+ {
+ return TRUE;
+ }
+
+ patch_dimx = llmin<U32>(patch_dimx, res - patch_origx);
+ patch_dimy = llmin<U32>(patch_dimy, res - patch_origy);
+
+ U32 num_of_tris = 0;
+ S32 px, py;
+ for (py = patch_origy; py < patch_origy + patch_dimy; py++)
+ {
+ for (px = patch_origx; px < patch_origx + patch_dimx; px++)
+ {
+ const U32 ind = py * sGrid->mPatchRes + px;
+ if (sGrid->mPatches[ind].visible() && sGrid->mTab[px][py] == 0)
+ {
+ num_of_tris += sGrid->mPatches[ind].numTris();
+ sGrid->mTab[px][py] = this;
+ }
+ }
+ }
+
+ if (num_of_tris == 0)
+ {
+ return TRUE;
+ }
+
+ if (drawable->getNumFaces() < 1)
+ {
+ drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER),
+ gWorldp->getDefaultWaterTexture());
+ }
+
+ LLFace *face;
+
+ face = drawable->getFace(0);
+ face->mCenterAgent = position_agent;
+
+ LLStrider<LLVector3> verticesp, normalsp;
+ LLStrider<LLVector2> texCoordsp;
+ U32 *indicesp;
+ S32 index_offset;
+
+ const F32 water_height = getRegion()->getWaterHeight();
+
+
+ face->setPrimType(LLTriangles);
+ face->setSize(3 * num_of_tris, 3 * num_of_tris);
+ index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
+ if (-1 == index_offset)
+ {
+ return TRUE;
+ }
+
+ U32 num_of_vtx = 0;
+
+ for (py = patch_origy; py < patch_origy + patch_dimy; py++)
+ {
+ for (px = patch_origx; px < patch_origx + patch_dimx; px++)
+ {
+ for (U8 h = 0; h < 2; h++)
+ {
+ const U32 ind = py * sGrid->mPatchRes + px;
+ if (!sGrid->mPatches[ind].visible() || sGrid->mTab[px][py] != this)
+ continue;
+ LLWaterTri* half = (LLWaterTri*) sGrid->mPatches[ind].half(h);
+ for (const LLWaterTri* tri = (LLWaterTri*) half->getFirstLeaf();
+ tri != NULL;
+ tri = (LLWaterTri*) tri->getNextLeaf())
+ {
+ /////// check for coordinates
+ *(verticesp++) = sGrid->vtx(tri->Lvtx(), water_height);
+ *(verticesp++) = sGrid->vtx(tri->Rvtx(), water_height);
+ *(verticesp++) = sGrid->vtx(tri->Tvtx(), water_height);
+
+ *(normalsp++) = sGrid->norm(tri->Lvtx());
+ *(normalsp++) = sGrid->norm(tri->Rvtx());
+ *(normalsp++) = sGrid->norm(tri->Tvtx());
+
+ *(indicesp++) = index_offset + num_of_vtx + 0;
+ *(indicesp++) = index_offset + num_of_vtx + 1;
+ *(indicesp++) = index_offset + num_of_vtx + 2;
+ num_of_vtx += 3;
+ }
+ }
+ }
+ }
+
+
+ LLPipeline::sCompiles++;
+ return TRUE;
+}
+
+
+
+BOOL LLVOWater::updateGeometryHeightFieldSimple(LLDrawable *drawable)
+{
+ LLVector3 position_agent = getPositionAgent();
+ const LLVector3 region_size = getScale();
+ const LLVector3 region_origin = position_agent - region_size * 0.5f;
+
+ S32 patch_origx = llround(region_origin.mV[VX] - sGrid->mRegionOrigin.mV[VX]) / sGrid->mRegionWidth;
+ S32 patch_origy = llround(region_origin.mV[VY] - sGrid->mRegionOrigin.mV[VY]) / sGrid->mRegionWidth;
+ S32 patch_dimx = llround(region_size.mV[VX]) / sGrid->mRegionWidth;
+ S32 patch_dimy = llround(region_size.mV[VY]) / sGrid->mRegionWidth;
+
+ static S32 res = sGrid->mPatchRes;
+ if (patch_origx < 0)
+ {
+ patch_dimx -= - patch_origx;
+ if (patch_dimx < 1)
+ {
+ return TRUE;
+ }
+ patch_origx = 0;
+ }
+ if (patch_origy < 0)
+ {
+ patch_dimy -= - patch_origy;
+ if (patch_dimy < 1)
+ {
+ return TRUE;
+ }
+ patch_origy = 0;
+ }
+ if (patch_origx >= res)
+ {
+ return TRUE;
+ }
+ if (patch_origy >= res)
+ {
+ return TRUE;
+ }
+
+ patch_dimx = llmin<U32>(patch_dimx, res - patch_origx);
+ patch_dimy = llmin<U32>(patch_dimy, res - patch_origy);
+
+
+ U32 num_of_regions = 0;
+ S32 px, py;
+
+ for (py = patch_origy; py < patch_origy + patch_dimy; py++)
+ {
+ for (px = patch_origx; px < patch_origx + patch_dimx; px++)
+ {
+ // if (sGrid->mTab[px][py] != 0)
+ // bool stop = true;
+ if (sGrid->mPatches[py * sGrid->mPatchRes + px].visible() && sGrid->mTab[px][py] == 0)
+ {
+ num_of_regions++;
+ sGrid->mTab[px][py] = this;
+ }
+ }
+ }
+
+ if (num_of_regions == 0)
+ {
+ return TRUE;
+ }
+
+ if (drawable->getNumFaces() < 1)
+ {
+ drawable->addFace((LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER),
+ gWorldp->getDefaultWaterTexture());
+ }
+
+ LLFace *face;
+
+ face = drawable->getFace(0);
+ face->mCenterAgent = position_agent;
+
+ LLStrider<LLVector3> verticesp, normalsp;
+ LLStrider<LLVector2> texCoordsp;
+ U32 *indicesp;
+ S32 index_offset;
+
+ const F32 water_height = getRegion()->getWaterHeight();
+
+ const U32 steps_in_region = sGrid->mStepsInRegion / sGrid->mResDecrease;
+ const U32 num_quads = steps_in_region * steps_in_region * num_of_regions;
+
+ face->setPrimType(LLTriangles);
+ face->setSize(4*num_quads, 6*num_quads);
+ index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
+ if (-1 == index_offset)
+ {
+ return TRUE;
+ }
+
+ U32 num_of_vtx = 0;
+
+ for (py = patch_origy; py < patch_origy + patch_dimy; py++)
+ {
+ for (px = patch_origx; px < patch_origx + patch_dimx; px++)
+ {
+ if (!sGrid->mPatches[py * sGrid->mPatchRes + px].visible() || sGrid->mTab[px][py] != this)
+ {
+ continue;
+ }
+
+ U32 orig_indx = px * sGrid->mStepsInRegion;
+ U32 orig_indy = py * sGrid->mStepsInRegion;
+
+ for (U32 qy = 0; qy < steps_in_region; qy++)
+ {
+ for (U32 qx = 0; qx < steps_in_region; qx++)
+ {
+ const S32 x0 = orig_indx + qx * sGrid->mResDecrease;
+ const S32 y0 = orig_indy + qy * sGrid->mResDecrease;
+ const S32 x1 = x0 + sGrid->mResDecrease;
+ const S32 y1 = y0 + sGrid->mResDecrease;
+
+ sGrid->setVertex(x0, y1, water_height, *(verticesp));
+ verticesp++;
+ sGrid->setVertex(x0, y0, water_height, *(verticesp));
+ verticesp++;
+ sGrid->setVertex(x1, y1, water_height, *(verticesp));
+ verticesp++;
+ sGrid->setVertex(x1, y0, water_height, *(verticesp));
+ verticesp++;
+ /*
+ *(verticesp++) = sGrid->vtx(x0, y1, water_height);
+ *(verticesp++) = sGrid->vtx(x0, y0, water_height);
+ *(verticesp++) = sGrid->vtx(x1, y1, water_height);
+ *(verticesp++) = sGrid->vtx(x1, y0, water_height);
+ */
+ *(normalsp++) = sGrid->norm(x0, y1);
+ *(normalsp++) = sGrid->norm(x0, y0);
+ *(normalsp++) = sGrid->norm(x1, y1);
+ *(normalsp++) = sGrid->norm(x1, y0);
+
+ const S32 curr_index_offset = index_offset + num_of_vtx;
+
+ *indicesp++ = curr_index_offset + 0;
+ *indicesp++ = curr_index_offset + 1;
+ *indicesp++ = curr_index_offset + 2;
+
+ *indicesp++ = curr_index_offset + 1;
+ *indicesp++ = curr_index_offset + 3;
+ *indicesp++ = curr_index_offset + 2;
+ num_of_vtx += 4;
+ }
+ }
+ }
+ }
+
+
+ LLPipeline::sCompiles++;
+ return TRUE;
+}
+
+void LLVOWater::initClass()
+{
+ sGrid = new LLWaterGrid;
+}
+
+void LLVOWater::cleanupClass()
+{
+ if (sGrid)
+ {
+ sGrid->cleanup();
+ delete sGrid;
+ sGrid = 0;
+ }
+}
+
+
+LLWaterGrid::LLWaterGrid() : mResIncrease(1)//0.5)
+{
+ init();
+}
+
+
+void LLWaterGrid::init()
+{
+ //mRegionOrigin = LLVector3(-2 * mRegionWidth, -2 * mRegionWidth, 0);
+ mRegionWidth = 256;
+ mPatchRes = 5;
+ mMaxGridSize = mPatchRes * mRegionWidth;
+ mMinStep = (U32)(WAVE_STEP * mResIncrease);
+
+ LLWaterTri::sMinStep = mMinStep;
+ LLWaterTri::sQueues = &mRoam;
+
+ setGridDim(mMaxGridSize / mMinStep);
+
+ mVtx = new LLVector3[mGridDim1 * mGridDim1];
+ mNorms = new LLVector3[mGridDim1 * mGridDim1];
+
+ mPatches = new LLWaterPatch[mPatchRes * mPatchRes];
+
+ mStepsInRegion = mRegionWidth / mMinStep;
+ const U32 max_div_level = 2 * (U32)(log((F32)mStepsInRegion) / log(2.0f));
+
+ for (U32 y = 0; y < mPatchRes; y++)
+ {
+ for (U32 x = 0; x < mPatchRes; x++)
+ {
+ LLVector3 patch_center(mRegionWidth * (x + 0.5f), mRegionWidth * (y + 0.5f), 0);
+
+ mPatches[y * mPatchRes + x].set(x * mStepsInRegion, y * mStepsInRegion,
+ mStepsInRegion, mRegionWidth, patch_center, max_div_level);
+ if (x > 0)
+ {
+ mPatches[y * mPatchRes + x].left()->setRight(mPatches[y * mPatchRes + x - 1].right());
+ mPatches[y * mPatchRes + x - 1].right()->setRight(mPatches[y * mPatchRes + x].left());
+ }
+ if (y > 0)
+ {
+ mPatches[y * mPatchRes + x].left()->setLeft(mPatches[(y - 1) * mPatchRes + x].right());
+ mPatches[(y - 1) * mPatchRes + x].right()->setLeft(mPatches[y * mPatchRes + x].left());
+ }
+ }
+ }
+}
+
+void LLWaterGrid::cleanup()
+{
+ delete[] mVtx;
+ mVtx = NULL;
+
+ delete[] mNorms;
+ mNorms = NULL;
+
+ delete[] mPatches;
+ mPatches = NULL;
+}
+
+
+void setVecZ(LLVector3& v)
+{
+ v.mV[VX] = 0;
+ v.mV[VY] = 0;
+ v.mV[VZ] = 1;
+}
+
+void LLWaterGrid::update()
+{
+ static LLViewerRegion* prev_region = gAgent.getRegion();
+ LLViewerRegion* region = gAgent.getRegion();
+
+ mRegionOrigin = region->getOriginAgent();
+ mRegionOrigin.mV[VX] -= 2 * mRegionWidth;
+ mRegionOrigin.mV[VY] -= 2 * mRegionWidth;
+ mRegionOrigin.mV[VZ] = 0;
+
+ const F32 clip_far = gCamera->getFar() - 31;
+ const F32 clip_far2 = clip_far * clip_far;
+
+ const LLVector3 camera_pos = gAgent.getCameraPositionAgent();
+ const LLVector3 look_at = gCamera->getAtAxis();
+
+
+ if (camera_pos.mV[VZ] > 200)
+ {
+ mResDecrease = 4;
+ }
+ else if (camera_pos.mV[VZ] > 100)
+ {
+ mResDecrease = 2;
+ }
+ else
+ {
+ mResDecrease = 1;
+ }
+
+
+ //U32 mResDecrease = res_decrease;
+ U32 res_decrease = 1;
+
+ const F32 res_change = mResIncrease;// * res_decrease ;
+
+ F32 height;
+
+ // Set the grid
+
+ //U32 fractions = 1;
+ U32 fractions_res = res_decrease;
+ if (res_change < 1)
+ {
+ //fractions = llround(1. / res_change);
+ fractions_res = llround(1.f / mResIncrease);
+ }
+
+
+ //const U32 fractions_res = fractions * res_decrease;
+
+ LLVector3 cur_pos;
+ U32 x, y;
+ U32 ind = 0;
+ for (y = 0; y < mGridDim1; y += fractions_res)
+ {
+ const F32 dispy = (F32)(y * mMinStep);//step;
+ for (x = 0; x < mGridDim1; x += fractions_res)
+ {
+ const F32 dispx = (F32)(x * mMinStep);//step;
+ cur_pos = mRegionOrigin;
+ cur_pos.mV[VX] += dispx;
+ cur_pos.mV[VY] += dispy;
+
+ const F32 x_dist = cur_pos.mV[VX] - camera_pos.mV[VX];
+ const F32 y_dist = cur_pos.mV[VY] - camera_pos.mV[VY];
+
+ if (x_dist * look_at.mV[VX] + y_dist * look_at.mV[VY] < 0)
+ {
+ mVtx[ind] = cur_pos;
+ setVecZ(mNorms[ind]);
+ ind++;
+ continue;
+ }
+
+ const F32 dist_to_vtx2 = x_dist * x_dist + y_dist * y_dist;
+ if (dist_to_vtx2 > .81 * clip_far2)
+ {
+ mVtx[ind] = cur_pos;
+ setVecZ(mNorms[ind]);
+ ind++;
+ continue;
+ }
+
+ mWater.getIntegerHeightAndNormal(llround(WAVE_STEP_INV * dispx),
+ llround(WAVE_STEP_INV * dispy), height, mNorms[ind]);
+
+ cur_pos.mV[VZ] += height;
+ mVtx[ind] = cur_pos;
+ ind++;
+ }
+ }
+
+ if (res_change < 1)
+ {
+ U32 fractions = llround(1.f / mResIncrease);
+ for (y = 0; y < mGridDim1; y += fractions_res)
+ {
+ for (x = 0; x < mGridDim; x += fractions_res)
+ {
+ const U32 ind00 = index(x, y);
+ const U32 ind01 = ind00 + fractions_res;
+ for (U32 frx = 1; frx < fractions; frx += res_decrease)
+ {
+ const U32 ind = ind00 + frx;
+ mNorms[ind] = LERP(mNorms[ind00], mNorms[ind01], frx * res_change);
+ mVtx[ind] = LERP( mVtx[ind00], mVtx[ind01], frx * res_change);
+ }
+ }
+ }
+ for (x = 0; x < mGridDim1; x += res_decrease)
+ {
+ for (y = 0; y < mGridDim; y += fractions_res)
+ {
+ const U32 ind00 = index(x, y);
+ const U32 ind10 = ind00 + fractions_res * mGridDim1;//(y + fractions) * quad_resx1 + x;
+ for (U32 fry = 1; fry < fractions; fry += res_decrease)
+ {
+ const U32 ind = ind00 + fry * mGridDim1;//(y + fry) * quad_resx1 + x;
+ mNorms[ind] = LERP(mNorms[ind00], mNorms[ind10], fry * res_change);
+ mVtx[ind] = LERP( mVtx[ind00], mVtx[ind10], fry * res_change);
+ }
+ }
+ }
+ }
+
+ if (gUseRoam)
+ {
+ updateTree(camera_pos, look_at, clip_far, prev_region != region);
+ }
+ else
+ {
+ updateVisibility(camera_pos, look_at, clip_far);
+ }
+
+ prev_region = region;
+
+
+ //mTab[0][0] = 0;
+ for (y = 0; y < mPatchRes; y++)
+ {
+ for (x = 0; x < mPatchRes; x++)
+ mTab[x][y] = 0;
+ }
+
+}
+
+void LLWaterGrid::updateTree(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far,
+ BOOL restart = FALSE)
+{
+ static S8 recalculate_frame = 0;
+
+ if (restart)
+ {
+ recalculate_frame = 0;
+ }
+
+ if (recalculate_frame == 0)
+ {
+ LLWaterTri::nextRound();
+ setCamPosition(LLWaterTri::sCam, camera_pos);
+ LLWaterTri::sClipFar = clip_far;
+
+
+ const U32 step = (U32)(WAVE_STEP * mResIncrease * mResDecrease);
+ const U32 steps_in_region = mRegionWidth / step;
+ LLWaterTri::sMaxDivLevel = 2 * llround(log((F32)steps_in_region) / log(2.0f));
+
+ for (U32 y = 0; y < mPatchRes; y++)
+ {
+ for (U32 x = 0; x < mPatchRes; x++)
+ {
+ U32 patch_ind = y * mPatchRes + x;
+ mPatches[patch_ind].updateTree(camera_pos, look_at, mRegionOrigin);
+ }
+ }
+
+ mRoam.process();
+
+ // debug
+ /*
+ for (y = 0; y < mPatchRes; y++)
+ {
+ for (U32 x = 0; x < mPatchRes; x++)
+ {
+ //mPatches[y * mPatchRes + x].checkUpToDate();
+ //mPatches[y * mPatchRes + x].checkConsistensy();
+ mPatches[y * mPatchRes + x].checkCount();
+ }
+ }
+ */
+ }
+ ++recalculate_frame;
+ recalculate_frame = recalculate_frame % 2;
+}
+
+void LLWaterGrid::updateVisibility(const LLVector3 &camera_pos, const LLVector3 &look_at, F32 clip_far)
+{
+ for (U32 y = 0; y < mPatchRes; y++)
+ {
+ for (U32 x = 0; x < mPatchRes; x++)
+ {
+ mPatches[y * mPatchRes + x].updateVisibility(camera_pos, look_at, mRegionOrigin);
+ }
+ }
+}
+
+
+void LLVOWater::setUseTexture(const BOOL use_texture)
+{
+ mUseTexture = use_texture;
+}
+
+F32 LLWaterSurface::agentDepth() const
+{
+ const LLViewerRegion* region = gAgent.getRegion();
+ LLVector3 position_agent = region->getOriginAgent();// getPositionAgent();
+ const LLVector3 region_origin = position_agent;
+ const LLVector3 camera_pos = gAgent.getCameraPositionAgent();
+
+ F32 height;
+ LLVector3 normal;
+
+ getHeightAndNormal(WAVE_STEP_INV * camera_pos.mV[VX],
+ WAVE_STEP_INV * camera_pos.mV[VY], height, normal);
+ F32 agent_water_height = gAgent.getRegion()->getWaterHeight();
+ return camera_pos.mV[VZ] - (agent_water_height + height);
+}
+
+////////////////////////////////////////////////
+
+
+void LLWaterSurface::getHeightAndNormal(F32 i, F32 j, F32& wave_height, LLVector3& normal) const
+{
+ S32 i_ind = llfloor(i);
+ S32 j_ind = llfloor(j);
+ F32 i_fr = i - i_ind;
+ F32 j_fr = j - j_ind;
+
+ i_ind = i_ind % N_RES;
+ j_ind = j_ind % N_RES;
+
+ S32 i_ind_next = i_ind + 1;
+ S32 j_ind_next = j_ind + 1;
+ if (i_ind_next == (S32)N_RES) i_ind_next = 0;
+ if (j_ind_next == (S32)N_RES) j_ind_next = 0;
+
+ const F32 i_fr1 = 1 - i_fr;
+ const F32 j_fr1 = 1 - j_fr;
+
+ const F32 hi0 = i_fr1 * height(i_ind, j_ind) + i_fr * height(i_ind_next, j_ind);
+ const F32 hi1 = i_fr1 * height(i_ind, j_ind_next) + i_fr * height(i_ind_next, j_ind_next);
+ wave_height = j_fr1 * hi0 + j_fr * hi1;
+
+ normal = i_fr1 * mNorms[i_ind][j_ind];
+ normal += i_fr * mNorms[i_ind_next][j_ind];
+ LLVector3 vi1 = i_fr1 * mNorms[i_ind][j_ind_next];
+ vi1 += i_fr * mNorms[i_ind_next][j_ind_next];
+ normal *= j_fr1;
+ normal += j_fr * vi1;
+
+ //normal.normVec();
+}
+
+void LLWaterSurface::getIntegerHeightAndNormal(S32 i, S32 j, F32& wave_height, LLVector3& normal) const
+{
+ S32 i_ind = i % N_RES;
+ S32 j_ind = j % N_RES;
+
+ wave_height = height(i_ind, j_ind);
+ normal = mNorms[i_ind][j_ind];
+}
+
+F32 LLWaterSurface::phillips(const LLVector2& k, const LLVector2& wind_n, F32 L, F32 L_small)
+{
+ F32 k2 = k * k;
+ F32 k_dot_wind = k * wind_n;
+ F32 spectrum = mA * (F32) exp(-1 / (L * L * k2)) / (k2 * k2) * (k_dot_wind * k_dot_wind / k2);
+
+ if (k_dot_wind < 0) spectrum *= .25f; // scale down waves that move opposite to the wind
+
+ F32 damp = (F32) exp(- k2 * L_small * L_small);
+
+ return (spectrum * damp);
+}
+
+
+
+void LLWaterSurface::initAmplitudes()
+{
+ U16 i, j;
+ LLVector2 k;
+ F32 sqrtPhillips;
+
+ const LLVector2 wind(mWind.mV);
+
+ LLVector2 wind_n = wind;
+ const F32 wind_vel = wind_n.normVec();
+
+ const F32 L = wind_vel * wind_vel / g; // largest wave arising from constant wind of speed wind_vel
+
+ const F32 L_small = L / 70; // eliminate waves with very small length (L_small << L)
+
+
+ for (i = 0; i <= N_RES; i++)
+ {
+ k.mV[VX] = (- (S32)N_RES_HALF + i) * (F_TWO_PI / WIDTH);
+ for (j = 0; j <= N_RES; j++)
+ {
+ k.mV[VY] = (- (S32)N_RES_HALF + j) * (F_TWO_PI / WIDTH);
+
+ const F32 k_mag = k.magVec();
+ mOmega[i][j] = (F32) sqrt(g * k_mag);
+
+ if (k_mag < F_APPROXIMATELY_ZERO)
+ sqrtPhillips = 0;
+ else
+ sqrtPhillips = (F32) sqrt(phillips(k, wind_n, L, L_small));
+
+ //const F32 r1 = rand() / (F32) RAND_MAX;
+ //const F32 r2 = rand() / (F32) RAND_MAX;
+ const F32 r1 = randGauss(0, 1);
+ const F32 r2 = randGauss(0, 1);
+
+ mHtilda0[i][j].re = sqrtPhillips * r1 * OO_SQRT2;
+ mHtilda0[i][j].im = sqrtPhillips * r2 * OO_SQRT2;
+
+ }
+ }
+
+ mPlan.init(N_RES, N_RES);
+ mInitialized = 1; // initialization complete
+}
+
+void LLWaterSurface::generateWaterHeightField(F64 t)
+{
+ S32 i, j;
+ S32 mi, mj; // -K indices
+ COMPLEX plus, minus;
+
+ if (!mInitialized) initAmplitudes();
+
+ for (i = 0; i < (S32)N_RES_HALF; i++)
+ {
+ mi = N_RES - i;
+ for (j = 0; j < (S32)N_RES ; j++)
+ {
+ mj = N_RES - j;
+
+ const F32 cos_wt = cosf(mOmega[i][j] * t); // = cos(-mOmega[i][j] * t)
+ const F32 sin_wt = sinf(mOmega[i][j] * t); // = -sin(-mOmega[i][j] * t)
+ plus.re = mHtilda0[i][j].re * cos_wt - mHtilda0[i][j].im * sin_wt;
+ plus.im = mHtilda0[i][j].re * sin_wt + mHtilda0[i][j].im * cos_wt;
+ minus.re = mHtilda0[mi][mj].re * cos_wt - mHtilda0[mi][mj].im * sin_wt;
+ minus.im = -mHtilda0[mi][mj].re * sin_wt - mHtilda0[mi][mj].im * cos_wt;
+
+ // now sum the plus and minus waves to get the total wave amplitude h
+ mHtilda[i * N_RES + j].re = plus.re + minus.re;
+ mHtilda[i * N_RES + j].im = plus.im + minus.im;
+ if (mi < (S32)N_RES && mj < (S32)N_RES)
+ {
+ mHtilda[mi * N_RES + mj].re = plus.re + minus.re;
+ mHtilda[mi * N_RES + mj].im = -plus.im - minus.im;
+ }
+ }
+ }
+
+ inverse_fft(mPlan, mHtilda, N_RES, N_RES);
+
+ calcNormals();
+}
+
+
+/*
+ * Computer normals by taking finite differences.
+ */
+
+void LLWaterSurface::calcNormals()
+{
+ LLVector3 n;
+
+ for (U32 i = 0; i < N_RES; i++)
+ {
+ for (U32 j = 0; j < N_RES; j++)
+ {
+ F32 px = heightWrapped(i + 1, j);
+ F32 mx = heightWrapped(i - 1, j);
+ F32 py = heightWrapped(i, j + 1);
+ F32 my = heightWrapped(i, j - 1);
+ F32 pxpy = heightWrapped(i + 1, j + 1);
+ F32 pxmy = heightWrapped(i + 1, j - 1);
+ F32 mxpy = heightWrapped(i - 1, j + 1);
+ F32 mxmy = heightWrapped(i - 1, j - 1);
+
+ n.mV[VX] = -((2 * px + pxpy + pxmy) - (2 * mx + mxpy + mxmy));
+ n.mV[VY] = -((2 * py + pxpy + mxpy) - (2 * my + pxmy + mxmy));
+ n.mV[VZ] = 8 * WIDTH / (F32) N_RES;
+ n.normVec();
+
+ mNorms[i][j] = n;
+ }
+ }
+}
+
+void LLVOWater::generateNewWaves(F64 time)
+{
+ getWaterSurface()->generateWaterHeightField(time);
+ sGrid->update();
+}
+