sceneSimpleZone.cpp
Engine/source/scene/zones/sceneSimpleZone.cpp
Public Variables
bool
For frame signal.
Detailed Description
Public Variables
bool gEditingMission
For frame signal.
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 "scene/zones/sceneSimpleZone.h" 26 27#include "scene/sceneRenderState.h" 28#include "scene/sceneManager.h" 29#include "scene/zones/sceneTraversalState.h" 30#include "scene/culling/sceneCullingVolume.h" 31#include "core/stream/bitStream.h" 32#include "console/engineAPI.h" 33#include "platform/profiler.h" 34 35 36extern bool gEditingMission; 37 38 39//----------------------------------------------------------------------------- 40 41SceneSimpleZone::SceneSimpleZone() 42 : mUseAmbientLightColor( false ), 43 mAmbientLightColor( 0.1f, 0.1f, 0.1f, 1.f ), 44 mIsRotated( false ) 45{ 46 // Box zones are unit cubes that are scaled to fit. 47 48 mObjScale.set( 10, 10, 10 ); 49 mObjBox.set( 50 Point3F( -0.5f, -0.5f, -0.5f ), 51 Point3F( 0.5f, 0.5f, 0.5f ) 52 ); 53} 54 55//----------------------------------------------------------------------------- 56 57void SceneSimpleZone::initPersistFields() 58{ 59 addGroup( "Lighting" ); 60 61 addProtectedField( "useAmbientLightColor", TypeBool, Offset( mUseAmbientLightColor, SceneSimpleZone ), 62 &_setUseAmbientLightColor, &defaultProtectedGetFn, 63 "Whether to use #ambientLightColor for ambient lighting in this zone or the global ambient color." ); 64 addProtectedField( "ambientLightColor", TypeColorF, Offset( mAmbientLightColor, SceneSimpleZone ), 65 &_setAmbientLightColor, &defaultProtectedGetFn, 66 "Color of ambient lighting in this zone.\n\n" 67 "Only used if #useAmbientLightColor is true." ); 68 69 endGroup( "Lighting" ); 70 71 Parent::initPersistFields(); 72} 73 74//----------------------------------------------------------------------------- 75 76String SceneSimpleZone::describeSelf() const 77{ 78 String str = Parent::describeSelf(); 79 str += String::ToString( "|zoneid: %i", getZoneRangeStart() ); 80 return str; 81} 82 83//----------------------------------------------------------------------------- 84 85bool SceneSimpleZone::onSceneAdd() 86{ 87 if( !Parent::onSceneAdd() ) 88 return false; 89 90 // Register our zone. 91 92 SceneZoneSpaceManager* manager = getSceneManager()->getZoneManager(); 93 if( manager ) 94 manager->registerZones( this, 1 ); 95 96 return true; 97} 98 99//----------------------------------------------------------------------------- 100 101U32 SceneSimpleZone::packUpdate( NetConnection* connection, U32 mask, BitStream* stream ) 102{ 103 U32 retMask = Parent::packUpdate( connection, mask, stream ); 104 105 if( stream->writeFlag( mask & AmbientMask ) ) 106 { 107 stream->writeFlag( mUseAmbientLightColor ); 108 stream->writeFloat( mAmbientLightColor.red, 7 ); 109 stream->writeFloat( mAmbientLightColor.green, 7 ); 110 stream->writeFloat( mAmbientLightColor.blue, 7 ); 111 stream->writeFloat( mAmbientLightColor.alpha, 7 ); 112 } 113 114 return retMask; 115} 116 117//----------------------------------------------------------------------------- 118 119void SceneSimpleZone::unpackUpdate( NetConnection* connection, BitStream* stream ) 120{ 121 Parent::unpackUpdate( connection, stream ); 122 123 if( stream->readFlag() ) // AmbientMask 124 { 125 mUseAmbientLightColor = stream->readFlag(); 126 mAmbientLightColor.red = stream->readFloat( 7 ); 127 mAmbientLightColor.green = stream->readFloat( 7 ); 128 mAmbientLightColor.blue = stream->readFloat( 7 ); 129 mAmbientLightColor.alpha = stream->readFloat( 7 ); 130 } 131} 132 133//----------------------------------------------------------------------------- 134 135void SceneSimpleZone::setUseAmbientLightColor( bool value ) 136{ 137 if( mUseAmbientLightColor == value ) 138 return; 139 140 mUseAmbientLightColor = value; 141 if( isServerObject() ) 142 setMaskBits( AmbientMask ); 143} 144 145//----------------------------------------------------------------------------- 146 147void SceneSimpleZone::setAmbientLightColor( const LinearColorF& color ) 148{ 149 mAmbientLightColor = color; 150 if( isServerObject() ) 151 setMaskBits( AmbientMask ); 152} 153 154//----------------------------------------------------------------------------- 155 156bool SceneSimpleZone::getZoneAmbientLightColor( U32 zone, LinearColorF& outColor ) const 157{ 158 AssertFatal( zone == getZoneRangeStart(), "SceneSimpleZone::getZoneAmbientLightColor - Invalid zone ID!" ); 159 160 if( !mUseAmbientLightColor ) 161 return false; 162 163 outColor = mAmbientLightColor; 164 return true; 165} 166 167//----------------------------------------------------------------------------- 168 169U32 SceneSimpleZone::getPointZone( const Point3F& p ) 170{ 171 if( !containsPoint( p ) ) 172 return SceneZoneSpaceManager::InvalidZoneId; 173 174 return getZoneRangeStart(); 175} 176 177//----------------------------------------------------------------------------- 178 179bool SceneSimpleZone::getOverlappingZones( const Box3F& aabb, U32* outZones, U32& outNumZones ) 180{ 181 PROFILE_SCOPE( SceneBoxZone_getOverlappingZones ); 182 183 bool isOverlapped = false; 184 bool isContained = false; 185 186 // If the zone has not been rotated, we can simply use straightforward 187 // AABB/AABB intersection based on the world boxes of the zone and the 188 // object. 189 // 190 // If, however, the zone has been rotated, then we must use the zone's 191 // OBB and test that against the object's AABB. 192 193 if( !mIsRotated ) 194 { 195 isOverlapped = mWorldBox.isOverlapped( aabb ); 196 isContained = isOverlapped && mWorldBox.isContained( aabb ); 197 } 198 else 199 { 200 // Check if the zone's OBB intersects the object's AABB. 201 202 isOverlapped = aabb.collideOrientedBox( 203 getScale() / 2.f, 204 getTransform() 205 ); 206 207 // If so, check whether the object's AABB is fully contained 208 // inside the zone's OBB. 209 210 if( isOverlapped ) 211 { 212 isContained = true; 213 214 for( U32 i = 0; i < Box3F::NUM_POINTS; ++ i ) 215 { 216 Point3F cornerPoint = aabb.computeVertex( i ); 217 if( !mOrientedWorldBox.isContained( cornerPoint ) ) 218 { 219 isContained = false; 220 break; 221 } 222 } 223 } 224 } 225 226 if( isOverlapped ) 227 { 228 outNumZones = 1; 229 outZones[ 0 ] = getZoneRangeStart(); 230 } 231 else 232 outNumZones = 0; 233 234 return !isContained; 235} 236 237//----------------------------------------------------------------------------- 238 239void SceneSimpleZone::setTransform( const MatrixF& mat ) 240{ 241 Parent::setTransform( mat ); 242 243 // Find out whether the zone has been rotated. 244 245 EulerF rotation = getTransform().toEuler(); 246 mIsRotated = !mIsZero( rotation.x ) || 247 !mIsZero( rotation.y ) || 248 !mIsZero( rotation.z ); 249 250 // Update the OBB. 251 252 _updateOrientedWorldBox(); 253} 254 255//----------------------------------------------------------------------------- 256 257void SceneSimpleZone::prepRenderImage( SceneRenderState* state ) 258{ 259 if( isRootZone() ) 260 return; 261 262 Parent::prepRenderImage( state ); 263} 264 265//----------------------------------------------------------------------------- 266 267void SceneSimpleZone::traverseZones( SceneTraversalState* state ) 268{ 269 traverseZones( state, getZoneRangeStart() ); 270} 271 272//----------------------------------------------------------------------------- 273 274void SceneSimpleZone::traverseZones( SceneTraversalState* state, U32 startZoneId ) 275{ 276 PROFILE_SCOPE( SceneSimpleZone_traverseZones ); 277 AssertFatal( startZoneId == getZoneRangeStart(), "SceneSimpleZone::traverseZones - Invalid start zone ID!" ); 278 279 // If we aren't the root of the traversal, do a number of checks 280 // to see if we can early out of the traversal here. The primary reason 281 // we don't do the checks if we are the root is because of the frustum 282 // near plane. The start zone of a traversal is selected based on the 283 // current viewpoint. However, that point still has some space in between 284 // it and the near plane so if we end up with a case where that's all the 285 // space that is needed to cull away our starting zone, we won't see any 286 // traversal at all and get a blank scene back even if the starting zone 287 // would actually hand the traversal over to other zones and eventually 288 // discover visible space. 289 290 if( state->getTraversalDepth() > 0 ) 291 { 292 // If we have already visited this zone in this traversal chain, 293 // exit out. This can happen when zones are grouped together. 294 // Note that this can also happen with the outdoor zone since it isn't 295 // convex. However, in that case, this acts as a nice side optimization 296 // we get since if the outdoor zone is already on the stack, our culling 297 // culling volume can only be smaller than the one we started with and thus 298 // by earlying out here, we prevent adding a pointless culling volume 299 // to the zone. 300 301 //TODO: would be nice to catch this via "visibility changed?" checks but 302 // that's non-trivial 303 304 if( state->haveVisitedZone( getZoneRangeStart() ) ) 305 return; 306 307 // First check whether we even intersect the given frustum at all. 308 309 if( mIsRotated ) 310 { 311 // Space has been rotated, so do a frustum/OBB check. 312 if( !state->getCurrentCullingVolume().test( _getOrientedWorldBox() ) ) 313 return; 314 } 315 else 316 { 317 // Space has not been rotated, so we can do a faster frustum/ABB check. 318 if( !state->getCurrentCullingVolume().test( getWorldBox() ) ) 319 return; 320 } 321 } 322 323 // Add the current culling volume to the culling state for this zone. 324 // If that doesn't result in new space becoming visible, we can terminate the traversal 325 // here. 326 327 if( !state->getCullingState()->addCullingVolumeToZone( startZoneId, state->getCurrentCullingVolume() ) ) 328 return; 329 330 // Add our occluders to the rendering state. 331 332 _addOccludersToCullingState( state->getCullingState() ); 333 334 // Merge the zone into the traversal area. 335 336 state->addToTraversedArea( getWorldBox() ); 337 338 // Push our zone ID on the traversal stack and traverse into our 339 // connected zone managers. 340 341 state->pushZone( startZoneId ); 342 _traverseConnectedZoneSpaces( state ); 343 state->popZone(); 344} 345 346//----------------------------------------------------------------------------- 347 348bool SceneSimpleZone::_setUseAmbientLightColor( void* object, const char* index, const char* data ) 349{ 350 SceneSimpleZone* zone = reinterpret_cast< SceneSimpleZone* >( object ); 351 zone->setUseAmbientLightColor( EngineUnmarshallData< bool>()( data ) ); 352 return false; 353} 354 355//----------------------------------------------------------------------------- 356 357bool SceneSimpleZone::_setAmbientLightColor( void* object, const char* index, const char* data ) 358{ 359 SceneSimpleZone* zone = reinterpret_cast< SceneSimpleZone* >( object ); 360 zone->setAmbientLightColor( EngineUnmarshallData< LinearColorF>()( data ) ); 361 return false; 362} 363