sun.cpp
Engine/source/environment/sun.cpp
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