sun.cpp

Engine/source/environment/sun.cpp

More...

Public Functions

ConsoleDocClass(Sun , "@brief A global light affecting your entire scene and optionally renders <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> corona <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "<a href="/coding/class/classsun/">Sun</a> is both the directional and ambient light <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> your entire <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" "@ingroup Atmosphere" )
DefineEngineMethod(Sun , animate , void , (F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation) , "animate( <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> duration, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> startAzimuth, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> endAzimuth, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> startElevation, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> endElevation )" )
DefineEngineMethod(Sun , apply , void , () , "" )

Detailed Description

Public Functions

ConsoleDocClass(Sun , "@brief A global light affecting your entire scene and optionally renders <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> corona <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "<a href="/coding/class/classsun/">Sun</a> is both the directional and ambient light <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> your entire <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">scene.\n\n</a>" "@ingroup Atmosphere" )

DefineEngineMethod(Sun , animate , void , (F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation) , "animate( <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> duration, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> startAzimuth, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> endAzimuth, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> startElevation, <a href="/coding/file/types_8h/#types_8h_1a841d3674577a1e86afdc2f4845f46c4b">F32</a> endElevation )" )

DefineEngineMethod(Sun , apply , void , () , "" )

IMPLEMENT_CO_NETOBJECT_V1(Sun )

  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 "environment/sun.h"
 26
 27#include "gfx/bitmap/gBitmap.h"
 28#include "math/mathIO.h"
 29#include "core/stream/bitStream.h"
 30#include "console/consoleTypes.h"
 31#include "console/engineAPI.h"
 32#include "scene/sceneManager.h"
 33#include "math/mathUtils.h"
 34#include "lighting/lightInfo.h"
 35#include "lighting/lightManager.h"
 36#include "scene/sceneRenderState.h"
 37#include "renderInstance/renderPassManager.h"
 38#include "sim/netConnection.h"
 39#include "environment/timeOfDay.h"
 40#include "gfx/gfxTransformSaver.h"
 41#include "materials/materialManager.h"
 42#include "materials/baseMatInstance.h"
 43#include "materials/sceneData.h"
 44#include "math/util/matrixSet.h"
 45
 46
 47IMPLEMENT_CO_NETOBJECT_V1(Sun);
 48
 49ConsoleDocClass( Sun,
 50   "@brief A global light affecting your entire scene and optionally renders a corona effect.\n\n"
 51
 52   "Sun is both the directional and ambient light for your entire scene.\n\n"   
 53
 54   "@ingroup Atmosphere"
 55);
 56
 57//-----------------------------------------------------------------------------
 58
 59Sun::Sun()
 60{
 61   mNetFlags.set(Ghostable | ScopeAlways);
 62   mTypeMask = EnvironmentObjectType | LightObjectType | StaticObjectType;
 63
 64   mLightColor.set(0.7f, 0.7f, 0.7f);
 65   mLightAmbient.set(0.3f, 0.3f, 0.3f);
 66   mBrightness = 1.0f;
 67   mSunAzimuth = 0.0f;
 68   mSunElevation = 35.0f;
 69   mCastShadows = true;
 70   mStaticRefreshFreq = 250;
 71   mDynamicRefreshFreq = 8;
 72
 73   mAnimateSun = false;
 74   mTotalTime = 0.0f;
 75   mCurrTime = 0.0f;
 76   mStartAzimuth = 0.0f;
 77   mEndAzimuth = 0.0f;
 78   mStartElevation = 0.0f;
 79   mEndElevation = 0.0f;
 80
 81   mLight = LightManager::createLightInfo();
 82   mLight->setType( LightInfo::Vector );
 83
 84   mFlareData = NULL;
 85   mFlareState.clear();
 86   mFlareScale = 1.0f;
 87
 88   mCoronaEnabled = true;
 89   mCoronaScale = 0.5f;
 90   mCoronaTint.set( 1.0f, 1.0f, 1.0f, 1.0f );
 91   mCoronaUseLightColor = true;
 92   mCoronaMatInst = NULL;
 93
 94   mMatrixSet = reinterpret_cast<MatrixSet *>(dMalloc_aligned(sizeof(MatrixSet), 16));
 95   constructInPlace(mMatrixSet);
 96
 97   mCoronaWorldRadius = 0.0f;
 98   mLightWorldPos = Point3F::Zero;
 99}
100
101Sun::~Sun()
102{
103   SAFE_DELETE( mLight );
104   SAFE_DELETE( mCoronaMatInst );
105   dFree_aligned(mMatrixSet);
106}
107
108bool Sun::onAdd()
109{
110   if ( !Parent::onAdd() )
111      return false;
112
113   // Register as listener to TimeOfDay update events
114   TimeOfDay::getTimeOfDayUpdateSignal().notify( this, &Sun::_updateTimeOfDay );
115
116   // Make this thing have a global bounds so that its 
117   // always returned from spatial light queries.
118   setGlobalBounds();
119   resetWorldBox();
120   setRenderTransform( mObjToWorld );
121   addToScene();
122
123   _initCorona();
124
125   // Update the light parameters.
126   _conformLights();
127
128   setProcessTick( true );
129
130   return true;
131}
132
133void Sun::onRemove()
134{   
135   TimeOfDay::getTimeOfDayUpdateSignal().remove( this, &Sun::_updateTimeOfDay );
136
137   removeFromScene();
138   Parent::onRemove();
139}
140
141void Sun::initPersistFields()
142{
143   addGroup( "Orbit" );
144
145      addField( "azimuth", TypeF32, Offset( mSunAzimuth, Sun ), 
146         "The horizontal angle of the sun measured clockwise from the positive Y world axis." );
147
148      addField( "elevation", TypeF32, Offset( mSunElevation, Sun ),
149         "The elevation angle of the sun above or below the horizon." );
150
151   endGroup( "Orbit" ); 
152
153   // We only add the basic lighting options that all lighting
154   // systems would use... the specific lighting system options
155   // are injected at runtime by the lighting system itself.
156
157   addGroup( "Lighting" );
158
159      addField( "color", TypeColorF, Offset( mLightColor, Sun ), 
160         "Color shading applied to surfaces in direct contact with light source.");
161
162      addField( "ambient", TypeColorF, Offset( mLightAmbient, Sun ), "Color shading applied to surfaces not "
163         "in direct contact with light source, such as in the shadows or interiors.");       
164
165      addField( "brightness", TypeF32, Offset( mBrightness, Sun ), 
166         "Adjust the Sun's global contrast/intensity");      
167
168      addField( "castShadows", TypeBool, Offset( mCastShadows, Sun ), 
169         "Enables/disables shadows cast by objects due to Sun light");    
170
171      //addField("staticRefreshFreq", TypeS32, Offset(mStaticRefreshFreq, Sun), "static shadow refresh rate (milliseconds)");
172      //addField("dynamicRefreshFreq", TypeS32, Offset(mDynamicRefreshFreq, Sun), "dynamic shadow refresh rate (milliseconds)");
173
174   endGroup( "Lighting" );
175
176   addGroup( "Corona" );
177
178      addField( "coronaEnabled", TypeBool, Offset( mCoronaEnabled, Sun ), 
179         "Enable or disable rendering of the corona sprite." );
180
181      addField( "coronaMaterial", TypeMaterialName, Offset( mCoronaMatName, Sun ),
182         "Texture for the corona sprite." );
183
184      addField( "coronaScale", TypeF32, Offset( mCoronaScale, Sun ),
185         "Controls size the corona sprite renders, specified as a fractional amount of the screen height." );
186
187      addField( "coronaTint", TypeColorF, Offset( mCoronaTint, Sun ),
188         "Modulates the corona sprite color ( if coronaUseLightColor is false )." );
189
190      addField( "coronaUseLightColor", TypeBool, Offset( mCoronaUseLightColor, Sun ),
191         "Modulate the corona sprite color by the color of the light ( overrides coronaTint )." );
192
193   endGroup( "Corona" );
194
195
196   addGroup( "Misc" );
197
198      addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, Sun ), 
199         "Datablock for the flare produced by the Sun" );
200
201      addField( "flareScale", TypeF32, Offset( mFlareScale, Sun ), 
202         "Changes the size and intensity of the flare." );
203
204   endGroup( "Misc" );
205
206   // Now inject any light manager specific fields.
207   LightManager::initLightFields();
208
209   Parent::initPersistFields();
210}
211
212void Sun::inspectPostApply()
213{
214   _conformLights();
215   setMaskBits(UpdateMask);
216}
217
218U32 Sun::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
219{
220   U32 retMask = Parent::packUpdate( conn, mask, stream );
221
222   if ( stream->writeFlag( mask & UpdateMask ) )
223   {
224      stream->write( mSunAzimuth );
225      stream->write( mSunElevation );
226      stream->write( mLightColor );
227      stream->write( mLightAmbient );
228      stream->write( mBrightness );      
229      stream->writeFlag( mCastShadows ); 
230      stream->write(mStaticRefreshFreq);
231      stream->write(mDynamicRefreshFreq);
232      stream->write( mFlareScale );
233
234      if ( stream->writeFlag( mFlareData ) )
235      {
236         stream->writeRangedU32( mFlareData->getId(),
237            DataBlockObjectIdFirst, 
238            DataBlockObjectIdLast );
239      }
240
241      stream->writeFlag( mCoronaEnabled );
242      stream->write( mCoronaMatName );
243      stream->write( mCoronaScale );
244      stream->write( mCoronaTint );
245      stream->writeFlag( mCoronaUseLightColor );
246
247      mLight->packExtended( stream ); 
248   }
249
250   return retMask;
251}
252
253void Sun::unpackUpdate( NetConnection *conn, BitStream *stream )
254{
255   Parent::unpackUpdate( conn, stream );
256
257   if ( stream->readFlag() ) // UpdateMask
258   {
259      stream->read( &mSunAzimuth );
260      stream->read( &mSunElevation );
261      stream->read( &mLightColor );
262      stream->read( &mLightAmbient );
263      stream->read( &mBrightness );      
264      mCastShadows = stream->readFlag();
265      stream->read(&mStaticRefreshFreq);
266      stream->read(&mDynamicRefreshFreq);
267      stream->read( &mFlareScale );
268
269      if ( stream->readFlag() )
270      {
271         SimObjectId id = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );  
272         LightFlareData *datablock = NULL;
273
274         if ( Sim::findObject( id, datablock ) )
275            mFlareData = datablock;
276         else
277         {
278            conn->setLastError( "Sun::unpackUpdate() - invalid LightFlareData!" );
279            mFlareData = NULL;
280         }
281      }
282      else
283         mFlareData = NULL;
284
285      mCoronaEnabled = stream->readFlag();
286      stream->read( &mCoronaMatName );
287      stream->read( &mCoronaScale );
288      stream->read( &mCoronaTint );
289      mCoronaUseLightColor = stream->readFlag();
290
291      mLight->unpackExtended( stream ); 
292   }
293
294   if ( isProperlyAdded() )
295   {
296      _initCorona();
297      _conformLights();
298   }
299}
300
301void Sun::submitLights( LightManager *lm, bool staticLighting )
302{
303   // The sun is a special light and needs special registration.
304   lm->setSpecialLight( LightManager::slSunLightType, mLight );
305}
306
307
308void Sun::advanceTime( F32 timeDelta )
309{
310   if (mAnimateSun)
311   {
312      if (mCurrTime >= mTotalTime)
313      {
314         mAnimateSun = false;
315         mCurrTime = 0.0f;
316      }
317      else
318      {
319         mCurrTime += timeDelta;
320
321         F32 fract   = mCurrTime / mTotalTime;
322         F32 inverse = 1.0f - fract;
323
324         F32 newAzimuth   = mStartAzimuth * inverse + mEndAzimuth * fract;
325         F32 newElevation = mStartElevation * inverse + mEndElevation * fract;
326
327         if (newAzimuth > 360.0f)
328            newAzimuth -= 360.0f;
329         if (newElevation > 360.0f)
330            newElevation -= 360.0f;
331
332         setAzimuth(newAzimuth);
333         setElevation(newElevation);
334      }
335   }
336}
337
338
339void Sun::prepRenderImage( SceneRenderState *state )
340{
341   // Only render into diffuse and reflect passes.
342
343   if( !state->isDiffusePass() &&
344       !state->isReflectPass() )
345      return;
346   
347   mLightWorldPos = state->getCameraPosition() - state->getFarPlane() * mLight->getDirection() * 0.9f;
348   F32 dist = ( mLightWorldPos - state->getCameraPosition() ).len();
349
350   F32 screenRadius = GFX->getViewport().extent.y * mCoronaScale * 0.5f;
351   mCoronaWorldRadius = screenRadius * dist / state->getWorldToScreenScale().y;   
352
353   // Render instance for Corona effect.   
354   if ( mCoronaEnabled && mCoronaMatInst )
355   {
356      mMatrixSet->setSceneProjection( GFX->getProjectionMatrix() );
357      mMatrixSet->setSceneView( GFX->getViewMatrix() );
358      mMatrixSet->setWorld( GFX->getWorldMatrix() );
359
360      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
361      ri->renderDelegate.bind( this, &Sun::_renderCorona );
362      ri->type = RenderPassManager::RIT_Sky;      
363      // Render after sky objects and before CloudLayer!
364      ri->defaultKey = 5;
365      ri->defaultKey2 = 0;
366      state->getRenderPass()->addInst( ri );
367   }
368
369   // LightFlareData handles rendering flare effects.
370   if ( mFlareData )
371   {
372      mFlareState.fullBrightness = mBrightness;
373      mFlareState.scale = mFlareScale;
374      mFlareState.lightInfo = mLight;
375      mFlareState.worldRadius = mCoronaWorldRadius;
376
377      mFlareState.lightMat.identity();
378      mFlareState.lightMat.setPosition( mLightWorldPos );
379
380      mFlareData->prepRender( state, &mFlareState );
381   }
382}
383
384void Sun::setAzimuth( F32 azimuth )
385{
386   mSunAzimuth = azimuth;
387   _conformLights();
388   setMaskBits( UpdateMask ); // TODO: Break out the masks to save bandwidth!
389}
390
391void Sun::setElevation( F32 elevation )
392{
393   mSunElevation = elevation;
394   _conformLights();
395   setMaskBits( UpdateMask ); // TODO: Break out the masks to save some space!
396}
397
398void Sun::setColor( const LinearColorF &color )
399{
400   mLightColor = color;
401   _conformLights();
402   setMaskBits( UpdateMask ); // TODO: Break out the masks to save some space!
403}
404
405void Sun::animate( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation )
406{
407   mAnimateSun = true;
408   mCurrTime = 0.0f;
409
410   mTotalTime = duration;
411
412   mStartAzimuth = startAzimuth;
413   mEndAzimuth = endAzimuth;
414   mStartElevation = startElevation;
415   mEndElevation = endElevation;
416}
417
418void Sun::_conformLights()
419{
420   // Build the light direction from the azimuth and elevation.
421   F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359));
422   F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360));
423   VectorF lightDirection;
424   MathUtils::getVectorFromAngles(lightDirection, yaw, pitch);
425   lightDirection.normalize();
426   mLight->setDirection( -lightDirection );
427   mLight->setBrightness( mBrightness );
428
429   // Now make sure the colors are within range.
430   mLightColor.clamp();
431   mLight->setColor( mLightColor );
432   mLightAmbient.clamp();
433   mLight->setAmbient( mLightAmbient );
434
435   // Optimization... disable shadows if the ambient and 
436   // directional color are the same.
437   bool castShadows = mLightColor != mLightAmbient && mCastShadows; 
438   mLight->setCastShadows( castShadows );
439   mLight->setStaticRefreshFreq(mStaticRefreshFreq);
440   mLight->setDynamicRefreshFreq(mDynamicRefreshFreq);
441}
442
443void Sun::_initCorona()
444{
445   if ( isServerObject() )
446      return;
447      
448   SAFE_DELETE( mCoronaMatInst );
449
450   if ( mCoronaMatName.isNotEmpty() )      
451      mCoronaMatInst = MATMGR->createMatInstance( mCoronaMatName, MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPCT>() );         
452}
453
454void Sun::_renderCorona( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
455{   
456   // Calculate Billboard Radius (in world units) to be constant, independent of distance.
457   // Takes into account distance, viewport size, and specified size in editor
458   F32 BBRadius = mCoronaWorldRadius;
459
460   mMatrixSet->restoreSceneViewProjection();   
461   
462   if ( state->isReflectPass() )
463      mMatrixSet->setProjection( state->getSceneManager()->getNonClipProjection() );
464
465   //mMatrixSet->setWorld( MatrixF::Identity );
466
467   // Initialize points with basic info
468   Point3F points[4];
469   points[0] = Point3F(-BBRadius, 0.0, -BBRadius);
470   points[1] = Point3F( -BBRadius, 0.0, BBRadius);
471   points[2] = Point3F( BBRadius, 0.0,  -BBRadius);
472   points[3] = Point3F(BBRadius, 0.0, BBRadius);
473
474   static const Point2F sCoords[4] = 
475   {
476      Point2F( 0.0f, 0.0f ),
477      Point2F( 0.0f, 1.0f ),      
478      Point2F( 1.0f, 0.0f ),
479      Point2F(1.0f, 1.0f)
480   };
481
482   // Get info we need to adjust points
483   const MatrixF &camView = state->getCameraTransform();
484
485   // Finalize points
486   for(S32 i = 0; i < 4; i++)
487   {
488      // align with camera
489      camView.mulV(points[i]);
490      // offset
491      points[i] += mLightWorldPos;
492   }
493
494   LinearColorF vertColor;
495   if ( mCoronaUseLightColor )
496      vertColor = mLightColor;
497   else
498      vertColor = mCoronaTint;
499
500   GFXVertexBufferHandle< GFXVertexPCT> vb;
501   vb.set( GFX, 4, GFXBufferTypeVolatile );
502   GFXVertexPCT *pVert = vb.lock();
503   if(!pVert) return;
504
505   for ( S32 i = 0; i < 4; i++ )
506   {
507      pVert->color.set( vertColor.toColorI());
508      pVert->point.set( points[i] );
509      pVert->texCoord.set( sCoords[i].x, sCoords[i].y );
510      pVert++;
511   }
512
513   vb.unlock();
514
515   // Setup SceneData struct.
516
517   SceneData sgData;
518   sgData.wireframe = GFXDevice::getWireframe();
519   sgData.visibility = 1.0f;
520
521   // Draw it
522
523   while ( mCoronaMatInst->setupPass( state, sgData ) )
524   {
525      mCoronaMatInst->setTransforms( *mMatrixSet, state );
526      mCoronaMatInst->setSceneInfo( state, sgData );
527
528      GFX->setVertexBuffer( vb );      
529      GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
530   }
531}
532
533void Sun::_updateTimeOfDay( TimeOfDay *timeOfDay, F32 time )
534{
535   setElevation( timeOfDay->getElevationDegrees() );
536   setAzimuth( timeOfDay->getAzimuthDegrees() );
537}
538
539void Sun::_onSelected()
540{
541#ifdef TORQUE_DEBUG
542   // Enable debug rendering on the light.
543   if( isClientObject() )
544      mLight->enableDebugRendering( true );
545#endif
546
547
548   Parent::_onSelected();
549}
550
551void Sun::_onUnselected()
552{
553#ifdef TORQUE_DEBUG
554   // Disable debug rendering on the light.
555   if( isClientObject() )
556      mLight->enableDebugRendering( false );
557#endif
558
559   Parent::_onUnselected();
560}
561
562DefineEngineMethod(Sun, apply, void, (), , "")
563{
564   object->inspectPostApply();
565}
566
567DefineEngineMethod(Sun, animate, void, ( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation ), , "animate( F32 duration, F32 startAzimuth, F32 endAzimuth, F32 startElevation, F32 endElevation )")
568{
569
570   object->animate(duration, startAzimuth, endAzimuth, startElevation, endElevation);
571}
572
573