viewer-beta / indra / newview / llwind.cpp

James Cook 003dd94 



Scott Lawrence 015080d 


davep ad384ab 
Scott Lawrence 015080d 



davep ad384ab 
Scott Lawrence 015080d 



Aaron Brashears a1e921b 
Scott Lawrence 015080d 


Aaron Brashears a1e921b 
Scott Lawrence 015080d 
Aaron Brashears a1e921b 
James Cook 003dd94 
















































































































































































































Steven Bennetts 706137d 
James Cook 003dd94 




























































Steven Bennetts 706137d 
James Cook 003dd94 


























































/** 
 * @file llwind.cpp
 * @brief LLWind class implementation
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

// 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 "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 = LLWorld::getInstance()->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 = LLWorld::getInstance()->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;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.