summaryrefslogtreecommitdiff
path: root/indra/newview/llwind.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llwind.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llwind.cpp')
-rw-r--r--indra/newview/llwind.cpp340
1 files changed, 340 insertions, 0 deletions
diff --git a/indra/newview/llwind.cpp b/indra/newview/llwind.cpp
new file mode 100644
index 0000000000..15b6304136
--- /dev/null
+++ b/indra/newview/llwind.cpp
@@ -0,0 +1,340 @@
+/**
+ * @file llwind.cpp
+ * @brief LLWind class implementation
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+// Wind is a lattice. It is computed on the simulator, and transmitted to the viewer.
+// It drives special effects like smoke blowing, trees bending, and grass wiggling.
+//
+// Currently wind lattice does not interpolate correctly to neighbors. This will need
+// work.
+
+#include "llviewerprecompiledheaders.h"
+#include "indra_constants.h"
+
+#include "llwind.h"
+
+// linden libraries
+#include "llgl.h"
+#include "patch_dct.h"
+#include "patch_code.h"
+
+// viewer
+#include "noise.h"
+#include "v4color.h"
+#include "viewer.h"
+#include "llagent.h"
+#include "llworld.h"
+
+
+const F32 CLOUD_DIVERGENCE_COEF = 0.5f;
+
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+LLWind::LLWind()
+: mSize(16),
+ mCloudDensityp(NULL)
+{
+ init();
+}
+
+
+LLWind::~LLWind()
+{
+ delete [] mVelX;
+ delete [] mVelY;
+ delete [] mCloudVelX;
+ delete [] mCloudVelY;
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Public Methods
+//////////////////////////////////////////////////////////////////////
+
+
+void LLWind::init()
+{
+ // Initialize vector data
+ mVelX = new F32[mSize*mSize];
+ mVelY = new F32[mSize*mSize];
+
+ mCloudVelX = new F32[mSize*mSize];
+ mCloudVelY = new F32[mSize*mSize];
+
+ S32 i;
+ for (i = 0; i < mSize*mSize; i++)
+ {
+ mVelX[i] = 0.5f;
+ mVelY[i] = 0.5f;
+ mCloudVelX[i] = 0.0f;
+ mCloudVelY[i] = 0.0f;
+ }
+}
+
+
+void LLWind::decompress(LLBitPack &bitpack, LLGroupHeader *group_headerp)
+{
+ if (!mCloudDensityp)
+ {
+ return;
+ }
+
+ LLPatchHeader patch_header;
+ S32 buffer[16*16];
+
+ init_patch_decompressor(group_headerp->patch_size);
+
+ // Don't use the packed group_header stride because the strides used on
+ // simulator and viewer are not equal.
+ group_headerp->stride = group_headerp->patch_size;
+ set_group_of_patch_header(group_headerp);
+
+ // X component
+ decode_patch_header(bitpack, &patch_header);
+ decode_patch(bitpack, buffer);
+ decompress_patch(mVelX, buffer, &patch_header);
+
+ // Y component
+ decode_patch_header(bitpack, &patch_header);
+ decode_patch(bitpack, buffer);
+ decompress_patch(mVelY, buffer, &patch_header);
+
+
+
+ S32 i, j, k;
+ // HACK -- mCloudVelXY is the same as mVelXY, except we add a divergence
+ // that is proportional to the gradient of the cloud density
+ // ==> this helps to clump clouds together
+ // NOTE ASSUMPTION: cloud density has the same dimensions as the wind field
+ // This needs to be fixed... causes discrepency at region boundaries
+
+ for (j=1; j<mSize-1; j++)
+ {
+ for (i=1; i<mSize-1; i++)
+ {
+ k = i + j * mSize;
+ *(mCloudVelX + k) = *(mVelX + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + 1) - *(mCloudDensityp + k - 1));
+ *(mCloudVelY + k) = *(mVelY + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + mSize) - *(mCloudDensityp + k - mSize));
+ }
+ }
+
+ i = mSize - 1;
+ for (j=1; j<mSize-1; j++)
+ {
+ k = i + j * mSize;
+ *(mCloudVelX + k) = *(mVelX + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k) - *(mCloudDensityp + k - 2));
+ *(mCloudVelY + k) = *(mVelY + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + mSize) - *(mCloudDensityp + k - mSize));
+ }
+ i = 0;
+ for (j=1; j<mSize-1; j++)
+ {
+ k = i + j * mSize;
+ *(mCloudVelX + k) = *(mVelX + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + 2) - *(mCloudDensityp + k));
+ *(mCloudVelY + k) = *(mVelY + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + mSize) - *(mCloudDensityp + k + mSize));
+ }
+ j = mSize - 1;
+ for (i=1; i<mSize-1; i++)
+ {
+ k = i + j * mSize;
+ *(mCloudVelX + k) = *(mVelX + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + 1) - *(mCloudDensityp + k - 1));
+ *(mCloudVelY + k) = *(mVelY + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k) - *(mCloudDensityp + k - 2*mSize));
+ }
+ j = 0;
+ for (i=1; i<mSize-1; i++)
+ {
+ k = i + j * mSize;
+ *(mCloudVelX + k) = *(mVelX + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + 1) - *(mCloudDensityp + k -1));
+ *(mCloudVelY + k) = *(mVelY + k) + CLOUD_DIVERGENCE_COEF * (*(mCloudDensityp + k + 2*mSize) - *(mCloudDensityp + k));
+ }
+}
+
+
+LLVector3 LLWind::getAverage()
+{
+ // Returns in average_wind the average wind velocity
+ LLVector3 average(0.0f, 0.0f, 0.0f);
+ S32 i, grid_count;
+ grid_count = mSize * mSize;
+ for (i = 0; i < grid_count; i++)
+ {
+ average.mV[VX] += mVelX[i];
+ average.mV[VY] += mVelY[i];
+ }
+
+ average *= 1.f/((F32)(grid_count)) * WIND_SCALE_HACK;
+ return average;
+}
+
+
+LLVector3 LLWind::getVelocityNoisy(const LLVector3 &pos_region, const F32 dim)
+{
+ // Resolve a value, using fractal summing to perturb the returned value
+ LLVector3 r_val(0,0,0);
+ F32 norm = 1.0f;
+ if (dim == 8)
+ {
+ norm = 1.875;
+ }
+ else if (dim == 4)
+ {
+ norm = 1.75;
+ }
+ else if (dim == 2)
+ {
+ norm = 1.5;
+ }
+
+ F32 temp_dim = dim;
+ while (temp_dim >= 1.0)
+ {
+ LLVector3 pos_region_scaled(pos_region * temp_dim);
+ r_val += getVelocity(pos_region_scaled) * (1.0f/temp_dim);
+ temp_dim /= 2.0;
+ }
+
+ return r_val * (1.0f/norm) * WIND_SCALE_HACK;
+}
+
+
+LLVector3 LLWind::getVelocity(const LLVector3 &pos_region)
+{
+ llassert(mSize == 16);
+ // Resolves value of wind at a location relative to SW corner of region
+ //
+ // Returns wind magnitude in X,Y components of vector3
+ LLVector3 r_val;
+ F32 dx,dy;
+ S32 k;
+
+ LLVector3 pos_clamped_region(pos_region);
+
+ F32 region_width_meters = gWorldPointer->getRegionWidthInMeters();
+
+ if (pos_clamped_region.mV[VX] < 0.f)
+ {
+ pos_clamped_region.mV[VX] = 0.f;
+ }
+ else if (pos_clamped_region.mV[VX] >= region_width_meters)
+ {
+ pos_clamped_region.mV[VX] = (F32) fmod(pos_clamped_region.mV[VX], region_width_meters);
+ }
+
+ if (pos_clamped_region.mV[VY] < 0.f)
+ {
+ pos_clamped_region.mV[VY] = 0.f;
+ }
+ else if (pos_clamped_region.mV[VY] >= region_width_meters)
+ {
+ pos_clamped_region.mV[VY] = (F32) fmod(pos_clamped_region.mV[VY], region_width_meters);
+ }
+
+
+ S32 i = llfloor(pos_clamped_region.mV[VX] * mSize / region_width_meters);
+ S32 j = llfloor(pos_clamped_region.mV[VY] * mSize / region_width_meters);
+ k = i + j*mSize;
+ dx = ((pos_clamped_region.mV[VX] * mSize / region_width_meters) - (F32) i);
+ dy = ((pos_clamped_region.mV[VY] * mSize / region_width_meters) - (F32) j);
+
+ if ((i < mSize-1) && (j < mSize-1))
+ {
+ // Interior points, no edges
+ r_val.mV[VX] = mVelX[k]*(1.0f - dx)*(1.0f - dy) +
+ mVelX[k + 1]*dx*(1.0f - dy) +
+ mVelX[k + mSize]*dy*(1.0f - dx) +
+ mVelX[k + mSize + 1]*dx*dy;
+ r_val.mV[VY] = mVelY[k]*(1.0f - dx)*(1.0f - dy) +
+ mVelY[k + 1]*dx*(1.0f - dy) +
+ mVelY[k + mSize]*dy*(1.0f - dx) +
+ mVelY[k + mSize + 1]*dx*dy;
+ }
+ else
+ {
+ r_val.mV[VX] = mVelX[k];
+ r_val.mV[VY] = mVelY[k];
+ }
+
+ r_val.mV[VZ] = 0.f;
+ return r_val * WIND_SCALE_HACK;
+}
+
+
+LLVector3 LLWind::getCloudVelocity(const LLVector3 &pos_region)
+{
+ llassert(mSize == 16);
+ // Resolves value of wind at a location relative to SW corner of region
+ //
+ // Returns wind magnitude in X,Y components of vector3
+ LLVector3 r_val;
+ F32 dx,dy;
+ S32 k;
+
+ LLVector3 pos_clamped_region(pos_region);
+
+ F32 region_width_meters = gWorldPointer->getRegionWidthInMeters();
+
+ if (pos_clamped_region.mV[VX] < 0.f)
+ {
+ pos_clamped_region.mV[VX] = 0.f;
+ }
+ else if (pos_clamped_region.mV[VX] >= region_width_meters)
+ {
+ pos_clamped_region.mV[VX] = (F32) fmod(pos_clamped_region.mV[VX], region_width_meters);
+ }
+
+ if (pos_clamped_region.mV[VY] < 0.f)
+ {
+ pos_clamped_region.mV[VY] = 0.f;
+ }
+ else if (pos_clamped_region.mV[VY] >= region_width_meters)
+ {
+ pos_clamped_region.mV[VY] = (F32) fmod(pos_clamped_region.mV[VY], region_width_meters);
+ }
+
+
+ S32 i = llfloor(pos_clamped_region.mV[VX] * mSize / region_width_meters);
+ S32 j = llfloor(pos_clamped_region.mV[VY] * mSize / region_width_meters);
+ k = i + j*mSize;
+ dx = ((pos_clamped_region.mV[VX] * mSize / region_width_meters) - (F32) i);
+ dy = ((pos_clamped_region.mV[VY] * mSize / region_width_meters) - (F32) j);
+
+ if ((i < mSize-1) && (j < mSize-1))
+ {
+ // Interior points, no edges
+ r_val.mV[VX] = mCloudVelX[k]*(1.0f - dx)*(1.0f - dy) +
+ mCloudVelX[k + 1]*dx*(1.0f - dy) +
+ mCloudVelX[k + mSize]*dy*(1.0f - dx) +
+ mCloudVelX[k + mSize + 1]*dx*dy;
+ r_val.mV[VY] = mCloudVelY[k]*(1.0f - dx)*(1.0f - dy) +
+ mCloudVelY[k + 1]*dx*(1.0f - dy) +
+ mCloudVelY[k + mSize]*dy*(1.0f - dx) +
+ mCloudVelY[k + mSize + 1]*dx*dy;
+ }
+ else
+ {
+ r_val.mV[VX] = mCloudVelX[k];
+ r_val.mV[VY] = mCloudVelY[k];
+ }
+
+ r_val.mV[VZ] = 0.f;
+ return r_val * WIND_SCALE_HACK;
+}
+
+
+void LLWind::setCloudDensityPointer(F32 *densityp)
+{
+ mCloudDensityp = densityp;
+}
+
+void LLWind::setOriginGlobal(const LLVector3d &origin_global)
+{
+ mOriginGlobal = origin_global;
+}
+
+