123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- //-----------------------------------------------------------------------------
- // 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 "gfx/gfxTextureManager.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"
- #include "sim/netConnection.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()
- : mLastTime( 0 ),
- mBaseColor( 0.9f, 0.9f, 0.9f, 1.0f ),
- mExposure( 1.0f ),
- mCoverage( 0.5f ),
- mWindSpeed( 1.0f )
- {
- mTypeMask |= EnvironmentObjectType | StaticObjectType;
- mNetFlags.set(Ghostable | ScopeAlways);
- mModelViewProjSC = NULL;
- mAmbientColorSC = NULL;
- mSunColorSC = NULL;
- mSunVecSC = NULL;
- mTexScaleSC = NULL;
- mBaseColorSC = NULL;
- mCoverageSC = NULL;
- mExposureSC = NULL;
- mEyePosWorldSC = NULL;
- mNormalHeightMapSC = NULL;
- mTexOffsetSC[0] = mTexOffsetSC[1] = mTexOffsetSC[2] = 0;
- 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;
- INIT_ASSET(Texture);
- }
- IMPLEMENT_CO_NETOBJECT_V1( CloudLayer );
- // ConsoleObject...
- bool CloudLayer::onAdd()
- {
- if ( !Parent::onAdd() )
- return false;
- setGlobalBounds();
- resetWorldBox();
- addToScene();
- LOAD_IMAGEASSET(Texture);
- if ( isClientObject() )
- {
- _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" );
- mNormalHeightMapSC = mShader->getShaderConstHandle( "$normalHeightMap" );
- // Create StateBlocks
- GFXStateBlockDesc desc;
- desc.setCullMode( GFXCullNone );
- desc.setBlend( true );
- desc.setZReadWrite( true, 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;
- mStateblock = GFX->createStateBlock( desc );
- }
- return true;
- }
- void CloudLayer::onRemove()
- {
- removeFromScene();
- Parent::onRemove();
- }
- void CloudLayer::initPersistFields()
- {
- addGroup( "CloudLayer" );
- INITPERSISTFIELD_IMAGEASSET(Texture, 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 );
- PACK_ASSET(conn, Texture);
-
- 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 );
- UNPACK_ASSET(conn, Texture);
- if(mTextureAssetId != StringTable->EmptyString())
- mTextureAsset = mTextureAssetId;
- for ( U32 i = 0; i < TEX_COUNT; i++ )
- {
- stream->read( &mTexScale[i] );
- stream->read( &mTexSpeed[i] );
- mathRead( *stream, &mTexDirection[i] );
- }
- stream->read( &mBaseColor );
- stream->read( &mCoverage );
- stream->read( &mExposure );
- stream->read( &mWindSpeed );
- F32 oldHeight = mHeight;
- stream->read( &mHeight );
- if ( isProperlyAdded() )
- {
- 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;
- if (!mTextureAsset || !mTextureAsset->isAssetValid())
- return;
- 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 LinearColorF &sunlight = state->getAmbientLightColor();
- Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
- mShaderConsts->setSafe( mAmbientColorSC, ambientColor );
- const LinearColorF &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( mNormalHeightMapSC->getSamplerRegister(), getTextureResource());
- GFX->setVertexBuffer( mVB );
- GFX->setPrimitiveBuffer( mPB );
- GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount );
- }
- // CloudLayer Internal Methods....
- 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();
- if(!pVert) return;
- 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();
- }
|