cloudLayer.cpp

Engine/source/environment/cloudLayer.cpp

More...

Public Functions

ConsoleDocClass(CloudLayer , "@brief A layer of clouds which change shape over time and are affected by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lighting.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> always renders overhead, following the camera. It is intended " "as part of the background of your level, rendering in front of Sky/<a href="/coding/class/classsun/">Sun</a> " "type objects and behind everything <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">else.\n\n</a>" "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 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> form and their general <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> and shape. " "The second two samples <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> how it changes over time;they are " "combined and used as modifiers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sample.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> is affected by scene lighting and is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used in " "scenes with dynamic lighting or time of day <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">changes.\n\n</a>" " @ingroup Atmosphere" )
GFXImplementVertexFormat(GFXCloudVertex )

Detailed Description

Public Functions

ConsoleDocClass(CloudLayer , "@brief A layer of clouds which change shape over time and are affected by scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">lighting.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> always renders overhead, following the camera. It is intended " "as part of the background of your level, rendering in front of Sky/<a href="/coding/class/classsun/">Sun</a> " "type objects and behind everything <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">else.\n\n</a>" "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 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> form and their general <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> and shape. " "The second two samples <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> how it changes over time;they are " "combined and used as modifiers <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">sample.\n\n</a>" "%<a href="/coding/class/classcloudlayer/">CloudLayer</a> is affected by scene lighting and is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be used in " "scenes with dynamic lighting or time of day <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">changes.\n\n</a>" " @ingroup Atmosphere" )

GFXImplementVertexFormat(GFXCloudVertex )

IMPLEMENT_CO_NETOBJECT_V1(CloudLayer )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "platform/profiler.h"
 26#include "console/consoleTypes.h"
 27#include "cloudLayer.h"
 28
 29#include "gfx/gfxTransformSaver.h"
 30#include "gfx/gfxTextureManager.h"
 31#include "core/stream/fileStream.h"
 32#include "core/stream/bitStream.h"
 33#include "scene/sceneRenderState.h"
 34#include "renderInstance/renderPassManager.h"
 35#include "gfx/primBuilder.h"
 36#include "materials/materialManager.h"
 37#include "materials/customMaterialDefinition.h"
 38#include "materials/shaderData.h"
 39#include "lighting/lightInfo.h"
 40#include "math/mathIO.h"
 41
 42ConsoleDocClass( CloudLayer,
 43   "@brief A layer of clouds which change shape over time and are affected by scene lighting.\n\n"
 44
 45   "%CloudLayer always renders overhead, following the camera. It is intended "
 46   "as part of the background of your level, rendering in front of Sky/Sun "
 47   "type objects and behind everything else.\n\n"
 48
 49   "The illusion of clouds forming and changing over time is controlled by the "
 50   "normal/opacity texture and the three sets of texture animation parameters. "
 51   "The texture is sampled three times.  The first sample defines overall cloud "
 52   "density, where clouds are likely to form and their general size and shape. "
 53   "The second two samples control how it changes over time; they are "
 54   "combined and used as modifiers to the first sample.\n\n"
 55
 56   "%CloudLayer is affected by scene lighting and is designed to be used in "
 57   "scenes with dynamic lighting or time of day changes.\n\n"
 58
 59   "@ingroup Atmosphere"
 60);
 61
 62GFXImplementVertexFormat( GFXCloudVertex )
 63{
 64   addElement( "POSITION", GFXDeclType_Float3 );
 65   addElement( "NORMAL", GFXDeclType_Float3 );
 66   addElement( "BINORMAL", GFXDeclType_Float3 );
 67   addElement( "TANGENT", GFXDeclType_Float3 );   
 68   addElement( "TEXCOORD", GFXDeclType_Float2, 0 );   
 69}
 70
 71U32 CloudLayer::smVertStride = 50;
 72U32 CloudLayer::smStrideMinusOne = smVertStride - 1;
 73U32 CloudLayer::smVertCount = smVertStride * smVertStride;
 74U32 CloudLayer::smTriangleCount = smStrideMinusOne * smStrideMinusOne * 2;
 75
 76CloudLayer::CloudLayer()
 77: mLastTime( 0 ),
 78  mBaseColor( 0.9f, 0.9f, 0.9f, 1.0f ),
 79  mExposure( 1.0f ),
 80  mCoverage( 0.5f ),
 81  mWindSpeed( 1.0f )
 82{
 83   mTypeMask |= EnvironmentObjectType | StaticObjectType;
 84   mNetFlags.set(Ghostable | ScopeAlways);
 85
 86   mModelViewProjSC = NULL;
 87   mAmbientColorSC = NULL;
 88   mSunColorSC = NULL;
 89   mSunVecSC = NULL;
 90   mTexScaleSC = NULL;
 91   mBaseColorSC = NULL;
 92   mCoverageSC = NULL;
 93   mExposureSC = NULL;
 94   mEyePosWorldSC = NULL;
 95   mNormalHeightMapSC = NULL;
 96
 97   mTexOffsetSC[0] = mTexOffsetSC[1] = mTexOffsetSC[2] = 0;
 98
 99   mTexScale[0] = 1.0;
100   mTexScale[1] = 1.0;
101   mTexScale[2] = 1.0;
102
103   mTexDirection[0].set( 1.0f, 0.0f );
104   mTexDirection[1].set( 0.0f, 1.0f );
105   mTexDirection[2].set( 0.5f, 0.0f );
106
107   mTexSpeed[0] = 0.005f;
108   mTexSpeed[1] = 0.005f;
109   mTexSpeed[2] = 0.005f;
110
111   mTexOffset[0] = mTexOffset[1] = mTexOffset[2] = Point2F::Zero;
112
113   mHeight = 4.0f;
114}
115
116IMPLEMENT_CO_NETOBJECT_V1( CloudLayer );
117
118// ConsoleObject...
119
120
121bool CloudLayer::onAdd()
122{
123   if ( !Parent::onAdd() )
124      return false;
125
126   setGlobalBounds();
127   resetWorldBox();
128
129   addToScene();
130
131   if ( isClientObject() )
132   {
133      _initTexture();
134      _initBuffers();
135
136      // Find ShaderData
137      ShaderData *shaderData;
138      mShader = Sim::findObject( "CloudLayerShader", shaderData ) ? 
139                  shaderData->getShader() : NULL;
140      if ( !mShader )
141      {
142         Con::errorf( "CloudLayer::onAdd - could not find CloudLayerShader" );
143         return false;
144      }
145
146      // Create ShaderConstBuffer and Handles
147      mShaderConsts = mShader->allocConstBuffer();
148      mModelViewProjSC = mShader->getShaderConstHandle( "$modelView" );
149      mEyePosWorldSC = mShader->getShaderConstHandle( "$eyePosWorld" );
150      mSunVecSC = mShader->getShaderConstHandle( "$sunVec" );
151      mTexOffsetSC[0] = mShader->getShaderConstHandle( "$texOffset0" );
152      mTexOffsetSC[1] = mShader->getShaderConstHandle( "$texOffset1" );
153      mTexOffsetSC[2] = mShader->getShaderConstHandle( "$texOffset2" );
154      mTexScaleSC = mShader->getShaderConstHandle( "$texScale" );
155      mAmbientColorSC = mShader->getShaderConstHandle( "$ambientColor" );
156      mSunColorSC = mShader->getShaderConstHandle( "$sunColor" );
157      mCoverageSC = mShader->getShaderConstHandle( "$cloudCoverage" );
158      mExposureSC = mShader->getShaderConstHandle( "$cloudExposure" );
159      mBaseColorSC = mShader->getShaderConstHandle( "$cloudBaseColor" );
160      mNormalHeightMapSC = mShader->getShaderConstHandle( "$normalHeightMap" );
161
162      // Create StateBlocks
163      GFXStateBlockDesc desc;
164      desc.setCullMode( GFXCullNone );
165      desc.setBlend( true );
166      desc.setZReadWrite( true, false );
167      desc.samplersDefined = true;
168      desc.samplers[0].addressModeU = GFXAddressWrap;
169      desc.samplers[0].addressModeV = GFXAddressWrap;
170      desc.samplers[0].addressModeW = GFXAddressWrap;
171      desc.samplers[0].magFilter = GFXTextureFilterLinear;
172      desc.samplers[0].minFilter = GFXTextureFilterLinear;
173      desc.samplers[0].mipFilter = GFXTextureFilterLinear;
174
175      mStateblock = GFX->createStateBlock( desc );   
176   }
177
178   return true;
179}
180
181void CloudLayer::onRemove()
182{
183   removeFromScene();
184
185   Parent::onRemove();
186}
187
188void CloudLayer::initPersistFields()
189{
190   addGroup( "CloudLayer" );     
191      
192      addField( "texture", TypeImageFilename, Offset( mTextureName, CloudLayer ),
193         "An RGBA texture which should contain normals and opacity (density)." );
194
195      addArray( "Textures", TEX_COUNT );
196
197         addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT,
198            "Controls the texture repeat of this slot." );
199
200         addField( "texDirection", TypePoint2F, Offset( mTexDirection, CloudLayer ), TEX_COUNT,
201            "Controls the direction this slot scrolls." );
202
203         addField( "texSpeed", TypeF32, Offset( mTexSpeed, CloudLayer ), TEX_COUNT,
204            "Controls the speed this slot scrolls." );
205
206      endArray( "Textures" );
207
208      addField( "baseColor", TypeColorF, Offset( mBaseColor, CloudLayer ),
209         "Base cloud color before lighting." );
210
211      addField( "exposure", TypeF32, Offset( mExposure, CloudLayer ),
212         "Brightness scale so CloudLayer can be overblown if desired." );
213      
214      addField( "coverage", TypeF32, Offset( mCoverage, CloudLayer ),
215         "Fraction of sky covered by clouds 0-1." );
216
217      addField( "windSpeed", TypeF32, Offset( mWindSpeed, CloudLayer ),
218         "Overall scalar to texture scroll speed." );
219
220      addField( "height", TypeF32, Offset( mHeight, CloudLayer ),
221         "Abstract number which controls the curvature and height of the dome mesh." );
222
223   endGroup( "CloudLayer" );
224
225   Parent::initPersistFields();
226}
227
228void CloudLayer::inspectPostApply()
229{
230   Parent::inspectPostApply();
231   setMaskBits( CloudLayerMask );
232}
233
234
235// NetObject...
236
237
238U32 CloudLayer::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
239{
240   U32 retMask = Parent::packUpdate( conn, mask, stream );
241
242   stream->write( mTextureName );
243   
244   for ( U32 i = 0; i < TEX_COUNT; i++ )
245   {
246      stream->write( mTexScale[i] );      
247      stream->write( mTexSpeed[i] );
248      mathWrite( *stream, mTexDirection[i] );
249   }
250
251   stream->write( mBaseColor );
252   stream->write( mCoverage );
253   stream->write( mExposure );
254   stream->write( mWindSpeed );
255   stream->write( mHeight );
256
257   return retMask;
258}
259
260void CloudLayer::unpackUpdate( NetConnection *conn, BitStream *stream )
261{
262   Parent::unpackUpdate( conn, stream );
263
264   String oldTextureName = mTextureName;
265   stream->read( &mTextureName );
266
267   for ( U32 i = 0; i < TEX_COUNT; i++ )
268   {
269      stream->read( &mTexScale[i] );      
270      stream->read( &mTexSpeed[i] );
271      mathRead( *stream, &mTexDirection[i] );
272   }
273
274   stream->read( &mBaseColor );
275
276   F32 oldCoverage = mCoverage;
277   stream->read( &mCoverage );
278   stream->read( &mExposure );
279
280   stream->read( &mWindSpeed );
281
282   F32 oldHeight = mHeight;
283   stream->read( &mHeight );
284
285   if ( isProperlyAdded() )
286   {
287      if ( ( oldTextureName != mTextureName ) || ( ( oldCoverage == 0.0f ) != ( mCoverage == 0.0f ) ) )
288         _initTexture();
289      if ( oldHeight != mHeight )
290         _initBuffers();
291   }
292}
293
294
295// SceneObject...
296
297
298void CloudLayer::prepRenderImage( SceneRenderState *state )
299{
300   PROFILE_SCOPE( CloudLayer_prepRenderImage );
301
302   if ( mCoverage <= 0.0f )
303      return;
304
305   if ( state->isDiffusePass() )
306   {
307      // Scroll textures...
308
309      U32 time = Sim::getCurrentTime();
310      F32 delta = (F32)( time - mLastTime ) / 1000.0f;
311      mLastTime = time;
312
313      for ( U32 i = 0; i < 3; i++ )
314      {
315         mTexOffset[i] += mTexDirection[i] * mTexSpeed[i] * delta * mWindSpeed;
316      }
317   }
318
319   // This should be sufficient for most objects that don't manage zones, and
320   // don't need to return a specialized RenderImage...
321
322   ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
323   ri->renderDelegate.bind( this, &CloudLayer::renderObject );
324   ri->type = RenderPassManager::RIT_Sky;
325   ri->defaultKey = 0;
326   ri->defaultKey2 = 0;
327   state->getRenderPass()->addInst( ri );
328}
329
330void CloudLayer::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mi )
331{
332   GFXTransformSaver saver;
333
334   const Point3F &camPos = state->getCameraPosition();
335   MatrixF xfm(true);
336   xfm.setPosition(camPos);
337   GFX->multWorld(xfm);   
338
339   if ( state->isReflectPass() )
340      GFX->setProjectionMatrix( state->getSceneManager()->getNonClipProjection() );
341
342   GFX->setShader( mShader );
343   GFX->setShaderConstBuffer( mShaderConsts );
344   GFX->setStateBlock( mStateblock );
345
346   // Set all the shader consts...
347
348   MatrixF xform(GFX->getProjectionMatrix());
349   xform *= GFX->getViewMatrix();
350   xform *= GFX->getWorldMatrix();
351
352   mShaderConsts->setSafe( mModelViewProjSC, xform );
353
354   mShaderConsts->setSafe( mEyePosWorldSC, camPos );
355
356   LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType);
357   const LinearColorF &sunlight = state->getAmbientLightColor();
358
359   Point3F ambientColor( sunlight.red, sunlight.green, sunlight.blue );
360   mShaderConsts->setSafe( mAmbientColorSC, ambientColor );   
361
362   const LinearColorF &sunColor = lightinfo->getColor();
363   Point3F data( sunColor.red, sunColor.green, sunColor.blue );
364   mShaderConsts->setSafe( mSunColorSC, data );
365
366   mShaderConsts->setSafe( mSunVecSC, lightinfo->getDirection() );
367
368   for ( U32 i = 0; i < TEX_COUNT; i++ )         
369      mShaderConsts->setSafe( mTexOffsetSC[i], mTexOffset[i] );
370
371   Point3F scale( mTexScale[0], mTexScale[1], mTexScale[2] );
372   mShaderConsts->setSafe( mTexScaleSC, scale );
373
374   Point3F color;
375   color.set( mBaseColor.red, mBaseColor.green, mBaseColor.blue );
376   mShaderConsts->setSafe( mBaseColorSC, color );
377
378   mShaderConsts->setSafe( mCoverageSC, mCoverage );
379
380   mShaderConsts->setSafe( mExposureSC, mExposure );
381
382   GFX->setTexture( mNormalHeightMapSC->getSamplerRegister(), mTexture );                            
383   GFX->setVertexBuffer( mVB );            
384   GFX->setPrimitiveBuffer( mPB );
385
386   GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, smVertCount, 0, smTriangleCount );
387}
388
389
390// CloudLayer Internal Methods....
391
392
393void CloudLayer::_initTexture()
394{
395   if ( mCoverage <= 0.0f )
396   {
397      mTexture = NULL;
398      return;
399   }
400
401   if ( mTextureName.isNotEmpty() )
402      mTexture.set( mTextureName, &GFXNormalMapProfile, "CloudLayer" );
403
404   if ( mTexture.isNull() )
405      mTexture.set( GFXTextureManager::getWarningTexturePath(), &GFXNormalMapProfile, "CloudLayer" );
406}
407
408void CloudLayer::_initBuffers()
409{      
410   // Vertex Buffer...
411
412   Point3F vertScale( 16.0f, 16.0f, mHeight );
413   F32 zOffset = -( mCos( mSqrt( 1.0f ) ) + 0.01f );
414   
415   mVB.set( GFX, smVertCount, GFXBufferTypeStatic );   
416   GFXCloudVertex *pVert = mVB.lock(); 
417   if(!pVert) return;
418
419   for ( U32 y = 0; y < smVertStride; y++ )
420   {
421      F32 v = ( (F32)y / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
422
423      for ( U32 x = 0; x < smVertStride; x++ )
424      {
425         F32 u = ( (F32)x / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
426
427         F32 sx = u;
428         F32 sy = v;
429         F32 sz = mCos( mSqrt( sx*sx + sy*sy ) ) + zOffset;
430         //F32 sz = 1.0f;
431         pVert->point.set( sx, sy, sz );
432         pVert->point *= vertScale;
433
434         // The vert to our right.
435         Point3F rpnt;
436
437         F32 ru = ( (F32)( x + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
438         F32 rv = v;
439
440         rpnt.x = ru;
441         rpnt.y = rv;
442         rpnt.z = mCos( mSqrt( rpnt.x*rpnt.x + rpnt.y*rpnt.y ) ) + zOffset;
443         rpnt *= vertScale;
444
445         // The vert to our front.
446         Point3F fpnt;
447
448         F32 fu = u;
449         F32 fv = ( (F32)( y + 1 ) / (F32)smStrideMinusOne - 0.5f ) * 2.0f;
450
451         fpnt.x = fu;
452         fpnt.y = fv;
453         fpnt.z = mCos( mSqrt( fpnt.x*fpnt.x + fpnt.y*fpnt.y ) ) + zOffset;
454         fpnt *= vertScale;
455
456         Point3F fvec = fpnt - pVert->point;
457         fvec.normalize();
458
459         Point3F rvec = rpnt - pVert->point;
460         rvec.normalize();
461
462         pVert->normal = mCross( fvec, rvec );
463         pVert->normal.normalize();
464         pVert->binormal = fvec;
465         pVert->tangent = rvec;
466         pVert->texCoord.set( u, v );   
467         pVert++;
468      }
469   }
470
471   mVB.unlock();
472
473
474   // Primitive Buffer...   
475
476   mPB.set( GFX, smTriangleCount * 3, smTriangleCount, GFXBufferTypeStatic );
477
478   U16 *pIdx = NULL;   
479   mPB.lock(&pIdx);     
480   U32 curIdx = 0; 
481
482   for ( U32 y = 0; y < smStrideMinusOne; y++ )
483   {
484      for ( U32 x = 0; x < smStrideMinusOne; x++ )
485      {
486         U32 offset = x + y * smVertStride;
487
488         pIdx[curIdx] = offset;
489         curIdx++;
490         pIdx[curIdx] = offset + 1;
491         curIdx++;
492         pIdx[curIdx] = offset + smVertStride + 1;
493         curIdx++;
494
495         pIdx[curIdx] = offset;
496         curIdx++;
497         pIdx[curIdx] = offset + smVertStride + 1;
498         curIdx++;
499         pIdx[curIdx] = offset + smVertStride;
500         curIdx++;
501      }
502   }
503
504   mPB.unlock();   
505}
506