123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- //-----------------------------------------------------------------------------
- // 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 "scene/zones/sceneSimpleZone.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "scene/zones/sceneTraversalState.h"
- #include "scene/culling/sceneCullingVolume.h"
- #include "core/stream/bitStream.h"
- #include "console/engineAPI.h"
- #include "platform/profiler.h"
- extern bool gEditingMission;
- //-----------------------------------------------------------------------------
- SceneSimpleZone::SceneSimpleZone()
- : mUseAmbientLightColor( false ),
- mAmbientLightColor( 0.1f, 0.1f, 0.1f, 1.f ),
- mIsRotated( false )
- {
- // Box zones are unit cubes that are scaled to fit.
- mObjScale.set( 10, 10, 10 );
- mObjBox.set(
- Point3F( -0.5f, -0.5f, -0.5f ),
- Point3F( 0.5f, 0.5f, 0.5f )
- );
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::initPersistFields()
- {
- docsURL;
- addGroup( "Lighting" );
- addProtectedField( "useAmbientLightColor", TypeBool, Offset( mUseAmbientLightColor, SceneSimpleZone ),
- &_setUseAmbientLightColor, &defaultProtectedGetFn,
- "Whether to use #ambientLightColor for ambient lighting in this zone or the global ambient color." );
- addProtectedField( "ambientLightColor", TypeColorF, Offset( mAmbientLightColor, SceneSimpleZone ),
- &_setAmbientLightColor, &defaultProtectedGetFn,
- "Color of ambient lighting in this zone.\n\n"
- "Only used if #useAmbientLightColor is true." );
- endGroup( "Lighting" );
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- String SceneSimpleZone::describeSelf() const
- {
- String str = Parent::describeSelf();
- str += String::ToString( "|zoneid: %i", getZoneRangeStart() );
- return str;
- }
- //-----------------------------------------------------------------------------
- bool SceneSimpleZone::onSceneAdd()
- {
- if( !Parent::onSceneAdd() )
- return false;
- // Register our zone.
- SceneZoneSpaceManager* manager = getSceneManager()->getZoneManager();
- if( manager )
- manager->registerZones( this, 1 );
- return true;
- }
- //-----------------------------------------------------------------------------
- U32 SceneSimpleZone::packUpdate( NetConnection* connection, U32 mask, BitStream* stream )
- {
- U32 retMask = Parent::packUpdate( connection, mask, stream );
- if( stream->writeFlag( mask & AmbientMask ) )
- {
- stream->writeFlag( mUseAmbientLightColor );
- stream->writeFloat( mAmbientLightColor.red, 7 );
- stream->writeFloat( mAmbientLightColor.green, 7 );
- stream->writeFloat( mAmbientLightColor.blue, 7 );
- stream->writeFloat( mAmbientLightColor.alpha, 7 );
- }
- return retMask;
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::unpackUpdate( NetConnection* connection, BitStream* stream )
- {
- Parent::unpackUpdate( connection, stream );
- if( stream->readFlag() ) // AmbientMask
- {
- mUseAmbientLightColor = stream->readFlag();
- mAmbientLightColor.red = stream->readFloat( 7 );
- mAmbientLightColor.green = stream->readFloat( 7 );
- mAmbientLightColor.blue = stream->readFloat( 7 );
- mAmbientLightColor.alpha = stream->readFloat( 7 );
- }
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::setUseAmbientLightColor( bool value )
- {
- if( mUseAmbientLightColor == value )
- return;
- mUseAmbientLightColor = value;
- if( isServerObject() )
- setMaskBits( AmbientMask );
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::setAmbientLightColor( const LinearColorF& color )
- {
- mAmbientLightColor = color;
- if( isServerObject() )
- setMaskBits( AmbientMask );
- }
- //-----------------------------------------------------------------------------
- bool SceneSimpleZone::getZoneAmbientLightColor( U32 zone, LinearColorF& outColor ) const
- {
- AssertFatal( zone == getZoneRangeStart(), "SceneSimpleZone::getZoneAmbientLightColor - Invalid zone ID!" );
- if( !mUseAmbientLightColor )
- return false;
- outColor = mAmbientLightColor;
- return true;
- }
- //-----------------------------------------------------------------------------
- U32 SceneSimpleZone::getPointZone( const Point3F& p )
- {
- if( !containsPoint( p ) )
- return SceneZoneSpaceManager::InvalidZoneId;
- return getZoneRangeStart();
- }
- //-----------------------------------------------------------------------------
- bool SceneSimpleZone::getOverlappingZones( const Box3F& aabb, U32* outZones, U32& outNumZones )
- {
- PROFILE_SCOPE( SceneBoxZone_getOverlappingZones );
- bool isOverlapped = false;
- bool isContained = false;
- // If the zone has not been rotated, we can simply use straightforward
- // AABB/AABB intersection based on the world boxes of the zone and the
- // object.
- //
- // If, however, the zone has been rotated, then we must use the zone's
- // OBB and test that against the object's AABB.
- if( !mIsRotated )
- {
- isOverlapped = mWorldBox.isOverlapped( aabb );
- isContained = isOverlapped && mWorldBox.isContained( aabb );
- }
- else
- {
- // Check if the zone's OBB intersects the object's AABB.
- isOverlapped = aabb.collideOrientedBox(
- getScale() / 2.f,
- getTransform()
- );
- // If so, check whether the object's AABB is fully contained
- // inside the zone's OBB.
- if( isOverlapped )
- {
- isContained = true;
- for( U32 i = 0; i < Box3F::NUM_POINTS; ++ i )
- {
- Point3F cornerPoint = aabb.computeVertex( i );
- if( !mOrientedWorldBox.isContained( cornerPoint ) )
- {
- isContained = false;
- break;
- }
- }
- }
- }
- if( isOverlapped )
- {
- outNumZones = 1;
- outZones[ 0 ] = getZoneRangeStart();
- }
- else
- outNumZones = 0;
- return !isContained;
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::setTransform( const MatrixF& mat )
- {
- Parent::setTransform( mat );
- // Find out whether the zone has been rotated.
- EulerF rotation = getTransform().toEuler();
- mIsRotated = !mIsZero( rotation.x ) ||
- !mIsZero( rotation.y ) ||
- !mIsZero( rotation.z );
- // Update the OBB.
- _updateOrientedWorldBox();
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::prepRenderImage( SceneRenderState* state )
- {
- if( isRootZone() )
- return;
- Parent::prepRenderImage( state );
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::traverseZones( SceneTraversalState* state )
- {
- traverseZones( state, getZoneRangeStart() );
- }
- //-----------------------------------------------------------------------------
- void SceneSimpleZone::traverseZones( SceneTraversalState* state, U32 startZoneId )
- {
- PROFILE_SCOPE( SceneSimpleZone_traverseZones );
- AssertFatal( startZoneId == getZoneRangeStart(), "SceneSimpleZone::traverseZones - Invalid start zone ID!" );
- // If we aren't the root of the traversal, do a number of checks
- // to see if we can early out of the traversal here. The primary reason
- // we don't do the checks if we are the root is because of the frustum
- // near plane. The start zone of a traversal is selected based on the
- // current viewpoint. However, that point still has some space in between
- // it and the near plane so if we end up with a case where that's all the
- // space that is needed to cull away our starting zone, we won't see any
- // traversal at all and get a blank scene back even if the starting zone
- // would actually hand the traversal over to other zones and eventually
- // discover visible space.
- if( state->getTraversalDepth() > 0 )
- {
- // If we have already visited this zone in this traversal chain,
- // exit out. This can happen when zones are grouped together.
- // Note that this can also happen with the outdoor zone since it isn't
- // convex. However, in that case, this acts as a nice side optimization
- // we get since if the outdoor zone is already on the stack, our culling
- // culling volume can only be smaller than the one we started with and thus
- // by earlying out here, we prevent adding a pointless culling volume
- // to the zone.
- //TODO: would be nice to catch this via "visibility changed?" checks but
- // that's non-trivial
- if( state->haveVisitedZone( getZoneRangeStart() ) )
- return;
- // First check whether we even intersect the given frustum at all.
- if( mIsRotated )
- {
- // Space has been rotated, so do a frustum/OBB check.
- if( !state->getCurrentCullingVolume().test( _getOrientedWorldBox() ) )
- return;
- }
- else
- {
- // Space has not been rotated, so we can do a faster frustum/ABB check.
- if( !state->getCurrentCullingVolume().test( getWorldBox() ) )
- return;
- }
- }
- // Add the current culling volume to the culling state for this zone.
- // If that doesn't result in new space becoming visible, we can terminate the traversal
- // here.
- if( !state->getCullingState()->addCullingVolumeToZone( startZoneId, state->getCurrentCullingVolume() ) )
- return;
- // Add our occluders to the rendering state.
- _addOccludersToCullingState( state->getCullingState() );
- // Merge the zone into the traversal area.
- state->addToTraversedArea( getWorldBox() );
- // Push our zone ID on the traversal stack and traverse into our
- // connected zone managers.
- state->pushZone( startZoneId );
- _traverseConnectedZoneSpaces( state );
- state->popZone();
- }
- //-----------------------------------------------------------------------------
- bool SceneSimpleZone::_setUseAmbientLightColor( void* object, const char* index, const char* data )
- {
- SceneSimpleZone* zone = reinterpret_cast< SceneSimpleZone* >( object );
- zone->setUseAmbientLightColor( EngineUnmarshallData< bool >()( data ) );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool SceneSimpleZone::_setAmbientLightColor( void* object, const char* index, const char* data )
- {
- SceneSimpleZone* zone = reinterpret_cast< SceneSimpleZone* >( object );
- zone->setAmbientLightColor( EngineUnmarshallData< LinearColorF >()( data ) );
- return false;
- }
|