mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
489 lines
14 KiB
C++
489 lines
14 KiB
C++
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Copyright (c) 2012 GarageGames, LLC
|
||
|
|
//
|
||
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
|
// of this software and associated documentation files (the "Software"), to
|
||
|
|
// deal in the Software without restriction, including without limitation the
|
||
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||
|
|
// furnished to do so, subject to the following conditions:
|
||
|
|
//
|
||
|
|
// The above copyright notice and this permission notice shall be included in
|
||
|
|
// all copies or substantial portions of the Software.
|
||
|
|
//
|
||
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
|
// IN THE SOFTWARE.
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
|
||
|
|
#include "platform/platform.h"
|
||
|
|
#include "platform/profiler.h"
|
||
|
|
#include "console/consoleTypes.h"
|
||
|
|
#include "cloudLayer.h"
|
||
|
|
|
||
|
|
#include "gfx/gfxTransformSaver.h"
|
||
|
|
#include "core/stream/fileStream.h"
|
||
|
|
#include "core/stream/bitStream.h"
|
||
|
|
#include "scene/sceneRenderState.h"
|
||
|
|
#include "renderInstance/renderPassManager.h"
|
||
|
|
#include "gfx/primBuilder.h"
|
||
|
|
#include "materials/materialManager.h"
|
||
|
|
#include "materials/customMaterialDefinition.h"
|
||
|
|
#include "materials/shaderData.h"
|
||
|
|
#include "lighting/lightInfo.h"
|
||
|
|
#include "math/mathIO.h"
|
||
|
|
|
||
|
|
ConsoleDocClass( CloudLayer,
|
||
|
|
"@brief A layer of clouds which change shape over time and are affected by scene lighting.\n\n"
|
||
|
|
|
||
|
|
"%CloudLayer always renders overhead, following the camera. It is intended "
|
||
|
|
"as part of the background of your level, rendering in front of Sky/Sun "
|
||
|
|
"type objects and behind everything else.\n\n"
|
||
|
|
|
||
|
|
"The illusion of clouds forming and changing over time is controlled by the "
|
||
|
|
"normal/opacity texture and the three sets of texture animation parameters. "
|
||
|
|
"The texture is sampled three times. The first sample defines overall cloud "
|
||
|
|
"density, where clouds are likely to form and their general size and shape. "
|
||
|
|
"The second two samples control how it changes over time; they are "
|
||
|
|
"combined and used as modifiers to the first sample.\n\n"
|
||
|
|
|
||
|
|
"%CloudLayer is affected by scene lighting and is designed to be used in "
|
||
|
|
"scenes with dynamic lighting or time of day changes.\n\n"
|
||
|
|
|
||
|
|
"@ingroup Atmosphere"
|
||
|
|
);
|
||
|
|
|
||
|
|
GFXImplementVertexFormat( GFXCloudVertex )
|
||
|
|
{
|
||
|
|
addElement( "POSITION", GFXDeclType_Float3 );
|
||
|
|
addElement( "NORMAL", GFXDeclType_Float3 );
|
||
|
|
addElement( "BINORMAL", GFXDeclType_Float3 );
|
||
|
|
addElement( "TANGENT", GFXDeclType_Float3 );
|
||
|
|
addElement( "TEXCOORD", GFXDeclType_Float2, 0 );
|
||
|
|
}
|
||
|
|
|
||
|
|
U32 CloudLayer::smVertStride = 50;
|
||
|
|
U32 CloudLayer::smStrideMinusOne = smVertStride - 1;
|
||
|
|
U32 CloudLayer::smVertCount = smVertStride * smVertStride;
|
||
|
|
U32 CloudLayer::smTriangleCount = smStrideMinusOne * smStrideMinusOne * 2;
|
||
|
|
|
||
|
|
CloudLayer::CloudLayer()
|
||
|
|
: mBaseColor( 0.9f, 0.9f, 0.9f, 1.0f ),
|
||
|
|
mCoverage( 0.5f ),
|
||
|
|
mExposure( 1.0f ),
|
||
|
|
mWindSpeed( 1.0f ),
|
||
|
|
mLastTime( 0 )
|
||
|
|
{
|
||
|
|
mTypeMask |= EnvironmentObjectType | StaticObjectType;
|
||
|
|
mNetFlags.set(Ghostable | ScopeAlways);
|
||
|
|
|
||
|
|
mTexScale[0] = 1.0;
|
||
|
|
mTexScale[1] = 1.0;
|
||
|
|
mTexScale[2] = 1.0;
|
||
|
|
|
||
|
|
mTexDirection[0].set( 1.0f, 0.0f );
|
||
|
|
mTexDirection[1].set( 0.0f, 1.0f );
|
||
|
|
mTexDirection[2].set( 0.5f, 0.0f );
|
||
|
|
|
||
|
|
mTexSpeed[0] = 0.005f;
|
||
|
|
mTexSpeed[1] = 0.005f;
|
||
|
|
mTexSpeed[2] = 0.005f;
|
||
|
|
|
||
|
|
mTexOffset[0] = mTexOffset[1] = mTexOffset[2] = Point2F::Zero;
|
||
|
|
|
||
|
|
mHeight = 4.0f;
|
||
|
|
}
|
||
|
|
|
||
|
|
IMPLEMENT_CO_NETOBJECT_V1( CloudLayer );
|
||
|
|
|
||
|
|
// ConsoleObject...
|
||
|
|
|
||
|
|
|
||
|
|
bool CloudLayer::onAdd()
|
||
|
|
{
|
||
|
|
if ( !Parent::onAdd() )
|
||
|
|
return false;
|
||
|
|
|
||
|
|
setGlobalBounds();
|
||
|
|
resetWorldBox();
|
||
|
|
|
||
|
|
addToScene();
|
||
|
|
|
||
|
|
if ( isClientObject() )
|
||
|
|
{
|
||
|
|
_initTexture();
|
||
|
|
_initBuffers();
|
||
|
|
|
||
|
|
// Find ShaderData
|
||
|
|
ShaderData *shaderData;
|
||
|
|
mShader = Sim::findObject( "CloudLayerShader", shaderData ) ?
|
||
|
|
shaderData->getShader() : NULL;
|
||
|
|
if ( !mShader )
|
||
|
|
{
|
||
|
|
Con::errorf( "CloudLayer::onAdd - could not find CloudLayerShader" );
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create ShaderConstBuffer and Handles
|
||
|
|
mShaderConsts = mShader->allocConstBuffer();
|
||
|
|
mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" );
|
||
|
|
mEyePosWorldSC = mShader->getShaderConstHandle( "$eyePosWorld" );
|
||
|
|
mSunVecSC = mShader->getShaderConstHandle( "$sunVec" );
|
||
|
|
mTexOffsetSC[0] = mShader->getShaderConstHandle( "$texOffset0" );
|
||
|
|
mTexOffsetSC[1] = mShader->getShaderConstHandle( "$texOffset1" );
|
||
|
|
mTexOffsetSC[2] = mShader->getShaderConstHandle( "$texOffset2" );
|
||
|
|
mTexScaleSC = mShader->getShaderConstHandle( "$texScale" );
|
||
|
|
mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" );
|
||
|
|
mSunColorSC = mShader->getShaderConstHandle( "$sunColor" );
|
||
|
|
mCoverageSC = mShader->getShaderConstHandle( "$cloudCoverage" );
|
||
|
|
mExposureSC = mShader->getShaderConstHandle( "$cloudExposure" );
|
||
|
|
mBaseColorSC = mShader->getShaderConstHandle( "$cloudBaseColor" );
|
||
|
|
|
||
|
|
// Create StateBlocks
|
||
|
|
GFXStateBlockDesc desc;
|
||
|
|
desc.setCullMode( GFXCullNone );
|
||
|
|
desc.setBlend( true );
|
||
|
|
desc.setZReadWrite( false, false );
|
||
|
|
desc.samplersDefined = true;
|
||
|
|
desc.samplers[0].addressModeU = GFXAddressWrap;
|
||
|
|
desc.samplers[0].addressModeV = GFXAddressWrap;
|
||
|
|
desc.samplers[0].addressModeW = GFXAddressWrap;
|
||
|
|
desc.samplers[0].magFilter = GFXTextureFilterLinear;
|
||
|
|
desc.samplers[0].minFilter = GFXTextureFilterLinear;
|
||
|
|
desc.samplers[0].mipFilter = GFXTextureFilterLinear;
|
||
|
|
desc.samplers[0].textureColorOp = GFXTOPModulate;
|
||
|
|
|
||
|
|
mStateblock = GFX->createStateBlock( desc );
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::onRemove()
|
||
|
|
{
|
||
|
|
removeFromScene();
|
||
|
|
|
||
|
|
Parent::onRemove();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::initPersistFields()
|
||
|
|
{
|
||
|
|
addGroup( "CloudLayer" );
|
||
|
|
|
||
|
|
addField( "texture", TypeImageFilename, Offset( mTextureName, CloudLayer ),
|
||
|
|
"An RGBA texture which should contain normals and opacity (density)." );
|
||
|
|
|
||
|
|
addArray( "Textures", TEX_COUNT );
|
||
|
|
|
||
|
|
addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT,
|
||
|
|
"Controls the texture repeat of this slot." );
|
||
|
|
|
||
|
|
addField( "texDirection", TypePoint2F, Offset( mTexDirection, CloudLayer ), TEX_COUNT,
|
||
|
|
"Controls the direction this slot scrolls." );
|
||
|
|
|
||
|
|
addField( "texSpeed", TypeF32, Offset( mTexSpeed, CloudLayer ), TEX_COUNT,
|
||
|
|
"Controls the speed this slot scrolls." );
|
||
|
|
|
||
|
|
endArray( "Textures" );
|
||
|
|
|
||
|
|
addField( "baseColor", TypeColorF, Offset( mBaseColor, CloudLayer ),
|
||
|
|
"Base cloud color before lighting." );
|
||
|
|
|
||
|
|
addField( "exposure", TypeF32, Offset( mExposure, CloudLayer ),
|
||
|
|
"Brightness scale so CloudLayer can be overblown if desired." );
|
||
|
|
|
||
|
|
addField( "coverage", TypeF32, Offset( mCoverage, CloudLayer ),
|
||
|
|
"Fraction of sky covered by clouds 0-1." );
|
||
|
|
|
||
|
|
addField( "windSpeed", TypeF32, Offset( mWindSpeed, CloudLayer ),
|
||
|
|
"Overall scalar to texture scroll speed." );
|
||
|
|
|
||
|
|
addField( "height", TypeF32, Offset( mHeight, CloudLayer ),
|
||
|
|
"Abstract number which controls the curvature and height of the dome mesh." );
|
||
|
|
|
||
|
|
endGroup( "CloudLayer" );
|
||
|
|
|
||
|
|
Parent::initPersistFields();
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::inspectPostApply()
|
||
|
|
{
|
||
|
|
Parent::inspectPostApply();
|
||
|
|
setMaskBits( CloudLayerMask );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// NetObject...
|
||
|
|
|
||
|
|
|
||
|
|
U32 CloudLayer::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
|
||
|
|
{
|
||
|
|
U32 retMask = Parent::packUpdate( conn, mask, stream );
|
||
|
|
|
||
|
|
stream->write( mTextureName );
|
||
|
|
|
||
|
|
for ( U32 i = 0; i < TEX_COUNT; i++ )
|
||
|
|
{
|
||
|
|
stream->write( mTexScale[i] );
|
||
|
|
stream->write( mTexSpeed[i] );
|
||
|
|
mathWrite( *stream, mTexDirection[i] );
|
||
|
|
}
|
||
|
|
|
||
|
|
stream->write( mBaseColor );
|
||
|
|
stream->write( mCoverage );
|
||
|
|
stream->write( mExposure );
|
||
|
|
stream->write( mWindSpeed );
|
||
|
|
stream->write( mHeight );
|
||
|
|
|
||
|
|
return retMask;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::unpackUpdate( NetConnection *conn, BitStream *stream )
|
||
|
|
{
|
||
|
|
Parent::unpackUpdate( conn, stream );
|
||
|
|
|
||
|
|
String oldTextureName = mTextureName;
|
||
|
|
stream->read( &mTextureName );
|
||
|
|
|
||
|
|
for ( U32 i = 0; i < TEX_COUNT; i++ )
|
||
|
|
{
|
||
|
|
stream->read( &mTexScale[i] );
|
||
|
|
stream->read( &mTexSpeed[i] );
|
||
|
|
mathRead( *stream, &mTexDirection[i] );
|
||
|
|
}
|
||
|
|
|
||
|
|
stream->read( &mBaseColor );
|
||
|
|
|
||
|
|
F32 oldCoverage = mCoverage;
|
||
|
|
stream->read( &mCoverage );
|
||
|
|
stream->read( &mExposure );
|
||
|
|
|
||
|
|
stream->read( &mWindSpeed );
|
||
|
|
|
||
|
|
F32 oldHeight = mHeight;
|
||
|
|
stream->read( &mHeight );
|
||
|
|
|
||
|
|
if ( isProperlyAdded() )
|
||
|
|
{
|
||
|
|
if ( ( oldTextureName != mTextureName ) || ( ( oldCoverage == 0.0f ) != ( mCoverage == 0.0f ) ) )
|
||
|
|
_initTexture();
|
||
|
|
if ( oldHeight != mHeight )
|
||
|
|
_initBuffers();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// SceneObject...
|
||
|
|
|
||
|
|
|
||
|
|
void CloudLayer::prepRenderImage( SceneRenderState *state )
|
||
|
|
{
|
||
|
|
PROFILE_SCOPE( CloudLayer_prepRenderImage );
|
||
|
|
|
||
|
|
if ( mCoverage <= 0.0f )
|
||
|
|
return;
|
||
|
|
|
||
|
|
if ( state->isDiffusePass() )
|
||
|
|
{
|
||
|
|
// Scroll textures...
|
||
|
|
|
||
|
|
U32 time = Sim::getCurrentTime();
|
||
|
|
F32 delta = (F32)( time - mLastTime ) / 1000.0f;
|
||
|
|
mLastTime = time;
|
||
|
|
|
||
|
|
for ( U32 i = 0; i < 3; i++ )
|
||
|
|
{
|
||
|
|
mTexOffset[i] += mTexDirection[i] * mTexSpeed[i] * delta * mWindSpeed;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// This should be sufficient for most objects that don't manage zones, and
|
||
|
|
// don't need to return a specialized RenderImage...
|
||
|
|
|
||
|
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||
|
|
ri->renderDelegate.bind( this, &CloudLayer::renderObject );
|
||
|
|
ri->type = RenderPassManager::RIT_Sky;
|
||
|
|
ri->defaultKey = 0;
|
||
|
|
ri->defaultKey2 = 0;
|
||
|
|
state->getRenderPass()->addInst( ri );
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
|
||
|
|
{
|
||
|
|
GFXTransformSaver saver;
|
||
|
|
|
||
|
|
const Point3F &camPos = state->getCameraPosition();
|
||
|
|
MatrixF xfm(true);
|
||
|
|
xfm.setPosition(camPos);
|
||
|
|
GFX->multWorld(xfm);
|
||
|
|
|
||
|
|
if ( state->isReflectPass() )
|
||
|
|
GFX->setProjectionMatrix( state->getSceneManager()->getNonClipProjection() );
|
||
|
|
|
||
|
|
GFX->setShader( mShader );
|
||
|
|
GFX->setShaderConstBuffer( mShaderConsts );
|
||
|
|
GFX->setStateBlock( mStateblock );
|
||
|
|
|
||
|
|
// Set all the shader consts...
|
||
|
|
|
||
|
|
MatrixF xform(GFX->getProjectionMatrix());
|
||
|
|
xform *= GFX->getViewMatrix();
|
||
|
|
xform *= GFX->getWorldMatrix();
|
||
|
|
|
||
|
|
mShaderConsts->setSafe( mModelViewProjSC, xform );
|
||
|
|
|
||
|
|
mShaderConsts->setSafe( mEyePosWorldSC, camPos );
|
||
|
|
|
||
|
|
LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType);
|
||
|
|
const ColorF &sunlight = state->getAmbientLightColor();
|
||
|
|
|
||
|
|
Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
|
||
|
|
mShaderConsts->setSafe( mAmbientColorSC, ambientColor );
|
||
|
|
|
||
|
|
const ColorF &sunColor = lightinfo->getColor();
|
||
|
|
Point3F data( sunColor.red, sunColor.green, sunColor.blue );
|
||
|
|
mShaderConsts->setSafe( mSunColorSC, data );
|
||
|
|
|
||
|
|
mShaderConsts->setSafe( mSunVecSC, lightinfo->getDirection() );
|
||
|
|
|
||
|
|
for ( U32 i = 0; i < TEX_COUNT; i++ )
|
||
|
|
mShaderConsts->setSafe( mTexOffsetSC[i], mTexOffset[i] );
|
||
|
|
|
||
|
|
Point3F scale( mTexScale[0], mTexScale[1], mTexScale[2] );
|
||
|
|
mShaderConsts->setSafe( mTexScaleSC, scale );
|
||
|
|
|
||
|
|
Point3F color;
|
||
|
|
color.set( mBaseColor.red, mBaseColor.green, mBaseColor.blue );
|
||
|
|
mShaderConsts->setSafe( mBaseColorSC, color );
|
||
|
|
|
||
|
|
mShaderConsts->setSafe( mCoverageSC, mCoverage );
|
||
|
|
|
||
|
|
mShaderConsts->setSafe( mExposureSC, mExposure );
|
||
|
|
|
||
|
|
GFX->setTexture( 0, mTexture );
|
||
|
|
GFX->setVertexBuffer( mVB );
|
||
|
|
GFX->setPrimitiveBuffer( mPB );
|
||
|
|
|
||
|
|
GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// CloudLayer Internal Methods....
|
||
|
|
|
||
|
|
|
||
|
|
void CloudLayer::_initTexture()
|
||
|
|
{
|
||
|
|
if ( mCoverage <= 0.0f )
|
||
|
|
{
|
||
|
|
mTexture = NULL;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( mTextureName.isNotEmpty() )
|
||
|
|
mTexture.set( mTextureName, &GFXDefaultStaticDiffuseProfile, "CloudLayer" );
|
||
|
|
|
||
|
|
if ( mTexture.isNull() )
|
||
|
|
mTexture.set( "core/art/warnmat", &GFXDefaultStaticDiffuseProfile, "CloudLayer" );
|
||
|
|
}
|
||
|
|
|
||
|
|
void CloudLayer::_initBuffers()
|
||
|
|
{
|
||
|
|
// Vertex Buffer...
|
||
|
|
|
||
|
|
Point3F vertScale( 16.0f, 16.0f, mHeight );
|
||
|
|
F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
|
||
|
|
|
||
|
|
mVB.set( GFX, smVertCount, GFXBufferTypeStatic );
|
||
|
|
GFXCloudVertex *pVert = mVB.lock();
|
||
|
|
|
||
|
|
for ( U32 y = 0; y < smVertStride; y++ )
|
||
|
|
{
|
||
|
|
F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
|
||
|
|
|
||
|
|
for ( U32 x = 0; x < smVertStride; x++ )
|
||
|
|
{
|
||
|
|
F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
|
||
|
|
|
||
|
|
F32 sx = u;
|
||
|
|
F32 sy = v;
|
||
|
|
F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset;
|
||
|
|
//F32 sz = 1.0f;
|
||
|
|
pVert->point.set( sx, sy, sz );
|
||
|
|
pVert->point *= vertScale;
|
||
|
|
|
||
|
|
// The vert to our right.
|
||
|
|
Point3F rpnt;
|
||
|
|
|
||
|
|
F32 ru = ( (F32)( x + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
|
||
|
|
F32 rv = v;
|
||
|
|
|
||
|
|
rpnt.x = ru;
|
||
|
|
rpnt.y = rv;
|
||
|
|
rpnt.z = mCos( mSqrt( rpnt.x*rpnt.x + rpnt.y*rpnt.y ) ) + zOffset;
|
||
|
|
rpnt *= vertScale;
|
||
|
|
|
||
|
|
// The vert to our front.
|
||
|
|
Point3F fpnt;
|
||
|
|
|
||
|
|
F32 fu = u;
|
||
|
|
F32 fv = ( (F32)( y + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
|
||
|
|
|
||
|
|
fpnt.x = fu;
|
||
|
|
fpnt.y = fv;
|
||
|
|
fpnt.z = mCos( mSqrt( fpnt.x*fpnt.x + fpnt.y*fpnt.y ) ) + zOffset;
|
||
|
|
fpnt *= vertScale;
|
||
|
|
|
||
|
|
Point3F fvec = fpnt - pVert->point;
|
||
|
|
fvec.normalize();
|
||
|
|
|
||
|
|
Point3F rvec = rpnt - pVert->point;
|
||
|
|
rvec.normalize();
|
||
|
|
|
||
|
|
pVert->normal = mCross( fvec, rvec );
|
||
|
|
pVert->normal.normalize();
|
||
|
|
pVert->binormal = fvec;
|
||
|
|
pVert->tangent = rvec;
|
||
|
|
pVert->texCoord.set( u, v );
|
||
|
|
pVert++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
mVB.unlock();
|
||
|
|
|
||
|
|
|
||
|
|
// Primitive Buffer...
|
||
|
|
|
||
|
|
mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic );
|
||
|
|
|
||
|
|
U16 *pIdx = NULL;
|
||
|
|
mPB.lock(&pIdx);
|
||
|
|
U32 curIdx = 0;
|
||
|
|
|
||
|
|
for ( U32 y = 0; y < smStrideMinusOne; y++ )
|
||
|
|
{
|
||
|
|
for ( U32 x = 0; x < smStrideMinusOne; x++ )
|
||
|
|
{
|
||
|
|
U32 offset = x + y * smVertStride;
|
||
|
|
|
||
|
|
pIdx[curIdx] = offset;
|
||
|
|
curIdx++;
|
||
|
|
pIdx[curIdx] = offset + 1;
|
||
|
|
curIdx++;
|
||
|
|
pIdx[curIdx] = offset + smVertStride + 1;
|
||
|
|
curIdx++;
|
||
|
|
|
||
|
|
pIdx[curIdx] = offset;
|
||
|
|
curIdx++;
|
||
|
|
pIdx[curIdx] = offset + smVertStride + 1;
|
||
|
|
curIdx++;
|
||
|
|
pIdx[curIdx] = offset + smVertStride;
|
||
|
|
curIdx++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
mPB.unlock();
|
||
|
|
}
|