Torque3D Documentation / _generateds / sceneZoneSpace.cpp

sceneZoneSpace.cpp

Engine/source/scene/zones/sceneZoneSpace.cpp

More...

Detailed Description

  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/sceneZoneSpace.h"
 26
 27#include "scene/zones/sceneTraversalState.h"
 28#include "scene/zones/sceneZoneSpaceManager.h"
 29#include "scene/sceneRenderState.h"
 30#include "sim/netConnection.h"
 31#include "core/stream/bitStream.h"
 32#include "console/engineAPI.h"
 33
 34
 35//#define DEBUG_SPEW
 36
 37
 38ClassChunker< SceneZoneSpace::ZoneSpaceRef> SceneZoneSpace::smZoneSpaceRefChunker;
 39
 40
 41//-----------------------------------------------------------------------------
 42
 43SceneZoneSpace::SceneZoneSpace()
 44   : mManager( NULL ),
 45     mZoneRangeStart( SceneZoneSpaceManager::InvalidZoneId ),
 46     mZoneGroup( InvalidZoneGroup ),
 47     mNumZones( 0 ),
 48     mZoneFlags( ZoneFlag_IsClosedOffSpace ),
 49     mConnectedZoneSpaces( NULL )
 50{
 51   VECTOR_SET_ASSOCIATION( mOccluders );
 52}
 53
 54//-----------------------------------------------------------------------------
 55
 56SceneZoneSpace::~SceneZoneSpace()
 57{
 58   AssertFatal( mConnectedZoneSpaces == NULL, "SceneZoneSpace::~SceneZoneSpace - Still have connected zone spaces!" );
 59}
 60
 61//-----------------------------------------------------------------------------
 62
 63void SceneZoneSpace::onSceneRemove()
 64{
 65   _disconnectAllZoneSpaces();
 66   Parent::onSceneRemove();
 67}
 68
 69//-----------------------------------------------------------------------------
 70
 71void SceneZoneSpace::initPersistFields()
 72{
 73   addGroup( "Zoning" );
 74
 75      addProtectedField( "zoneGroup", TypeS32, Offset( mZoneGroup, SceneZoneSpace ),
 76         &_setZoneGroup, &defaultProtectedGetFn,
 77         "ID of group the zone is part of." );
 78
 79   endGroup( "Zoning" );
 80
 81   Parent::initPersistFields();
 82}
 83
 84//-----------------------------------------------------------------------------
 85
 86bool SceneZoneSpace::writeField( StringTableEntry fieldName, const char* value )
 87{
 88   // Don't write zoneGroup field if at default.
 89   static StringTableEntry sZoneGroup = StringTable->insert( "zoneGroup" );
 90   if( fieldName == sZoneGroup && getZoneGroup() == InvalidZoneGroup )
 91      return false;
 92
 93   return Parent::writeField( fieldName, value );
 94}
 95
 96//-----------------------------------------------------------------------------
 97
 98void SceneZoneSpace::setZoneGroup( U32 group )
 99{
100   if( mZoneGroup == group )
101      return;
102
103   mZoneGroup = group;
104   setMaskBits( ZoneGroupMask );
105
106   // Rezone to establish new connectivity.
107
108   if( mManager )
109      mManager->notifyObjectChanged( this );
110}
111
112//-----------------------------------------------------------------------------
113
114U32 SceneZoneSpace::packUpdate( NetConnection* connection, U32 mask, BitStream* stream )
115{
116   U32 retMask = Parent::packUpdate( connection, mask, stream );
117
118   if( stream->writeFlag( mask & ZoneGroupMask ) )
119      stream->write( mZoneGroup );
120
121   return retMask;
122}
123
124//-----------------------------------------------------------------------------
125
126void SceneZoneSpace::unpackUpdate( NetConnection* connection, BitStream* stream )
127{
128   Parent::unpackUpdate( connection, stream );
129
130   if( stream->readFlag() ) // ZoneGroupMask
131   {
132      U32 zoneGroup;
133      stream->read( &zoneGroup );
134      setZoneGroup( zoneGroup );
135   }
136}
137
138//-----------------------------------------------------------------------------
139
140bool SceneZoneSpace::getOverlappingZones( SceneObject* obj, U32* outZones, U32& outNumZones )
141{
142   return getOverlappingZones( obj->getWorldBox(), outZones, outNumZones );
143}
144
145//-----------------------------------------------------------------------------
146
147void SceneZoneSpace::_onZoneAddObject( SceneObject* object, const U32* zoneIDs, U32 numZones )
148{
149   if( object->isVisualOccluder() )
150      _addOccluder( object );
151
152   // If this isn't the root zone and the object is zone space,
153   // see if we should automatically connect the two.
154   
155   if( !isRootZone() && object->getTypeMask() & ZoneObjectType )
156   {
157      SceneZoneSpace* zoneSpace = dynamic_cast< SceneZoneSpace* >( object );
158
159      // Don't connect a zone space that has the same closed off status
160      // that we have except it is assigned to the same zone group.
161
162      if( zoneSpace &&
163          ( zoneSpace->mZoneFlags.test( ZoneFlag_IsClosedOffSpace ) != mZoneFlags.test( ZoneFlag_IsClosedOffSpace ) ||
164            ( zoneSpace->getZoneGroup() == getZoneGroup() &&
165              zoneSpace->getZoneGroup() != InvalidZoneGroup ) ) &&
166          _automaticallyConnectZoneSpace( zoneSpace ) )
167      {
168         connectZoneSpace( zoneSpace );
169      }
170   }
171}
172
173//-----------------------------------------------------------------------------
174
175void SceneZoneSpace::_onZoneRemoveObject( SceneObject* object )
176{
177   if( object->isVisualOccluder() )
178      _removeOccluder( object );
179
180   if( !isRootZone() && object->getTypeMask() & ZoneObjectType )
181   {
182      SceneZoneSpace* zoneSpace = dynamic_cast< SceneZoneSpace* >( object );
183      if( zoneSpace )
184         disconnectZoneSpace( zoneSpace );
185   }
186}
187
188//-----------------------------------------------------------------------------
189
190bool SceneZoneSpace::_automaticallyConnectZoneSpace( SceneZoneSpace* zoneSpace ) const
191{
192   //TODO: This is suboptimal.  While it prevents the most blatantly wrong automatic connections,
193   //  we need a true polyhedron/polyhedron intersection to accurately determine zone intersection
194   //  when it comes to automatic connections.
195
196   U32 numZones = 0;
197   U32 zones[ SceneObject::MaxObjectZones ];
198
199   zoneSpace->getOverlappingZones( getWorldBox(), zones, numZones );
200   
201   return ( numZones > 0 );
202}
203
204//-----------------------------------------------------------------------------
205
206void SceneZoneSpace::connectZoneSpace( SceneZoneSpace* zoneSpace )
207{
208   // If the zone space is already in the list, do nothing.
209
210   for( ZoneSpaceRef* ref = mConnectedZoneSpaces; ref != NULL; ref = ref->mNext )
211      if( ref->mZoneSpace == zoneSpace )
212         return;
213
214   // Link the zone space to the zone space refs.
215
216   ZoneSpaceRef* ref = smZoneSpaceRefChunker.alloc();
217
218   ref->mZoneSpace = zoneSpace;
219   ref->mNext = mConnectedZoneSpaces;
220
221   mConnectedZoneSpaces = ref;
222
223   #ifdef DEBUG_SPEW
224   Platform::outputDebugString( "[SceneZoneSpace] Connecting %i-%i to %i-%i",
225      getZoneRangeStart(), getZoneRangeStart() + getZoneRange(),
226      zoneSpace->getZoneRangeStart(), zoneSpace->getZoneRangeStart() + zoneSpace->getZoneRange()
227   );
228   #endif
229}
230
231//-----------------------------------------------------------------------------
232
233void SceneZoneSpace::disconnectZoneSpace( SceneZoneSpace* zoneSpace )
234{
235   ZoneSpaceRef* prev = NULL;
236   for( ZoneSpaceRef* ref = mConnectedZoneSpaces; ref != NULL; prev = ref, ref = ref->mNext )
237      if( ref->mZoneSpace == zoneSpace )
238      {
239         if( prev )
240            prev->mNext = ref->mNext;
241         else
242            mConnectedZoneSpaces = ref->mNext;
243
244         #ifdef DEBUG_SPEW
245         Platform::outputDebugString( "[SceneZoneSpace] Disconnecting %i-%i from %i-%i",
246            getZoneRangeStart(), getZoneRangeStart() + getZoneRange(),
247            zoneSpace->getZoneRangeStart(), zoneSpace->getZoneRangeStart() + zoneSpace->getZoneRange()
248         );
249         #endif
250
251         smZoneSpaceRefChunker.free( ref );
252         break;
253      }
254}
255
256//-----------------------------------------------------------------------------
257
258void SceneZoneSpace::_disconnectAllZoneSpaces()
259{
260   #ifdef DEBUG_SPEW
261   if( mConnectedZoneSpaces != NULL )
262      Platform::outputDebugString( "[SceneZoneSpace] Disconnecting all from %i-%i",
263         getZoneRangeStart(), getZoneRangeStart() + getZoneRange()
264      );
265   #endif
266   
267   for( ZoneSpaceRef* ref = mConnectedZoneSpaces; ref != NULL; )
268   {
269      ZoneSpaceRef* next = ref->mNext;
270      smZoneSpaceRefChunker.free( ref );
271      ref = next;
272   }
273   mConnectedZoneSpaces = NULL;
274}
275
276//-----------------------------------------------------------------------------
277
278void SceneZoneSpace::_addOccluder( SceneObject* object )
279{
280   AssertFatal( !mOccluders.contains( object ), "SceneZoneSpace::_addOccluder - Occluder already added to this zone space!" );
281   mOccluders.push_back( object );
282}
283
284//-----------------------------------------------------------------------------
285
286void SceneZoneSpace::_removeOccluder( SceneObject* object )
287{
288   const U32 numOccluders = mOccluders.size();
289   for( U32 i = 0; i < numOccluders; ++ i )
290      if( mOccluders[ i ] == object )
291      {
292         mOccluders.erase_fast( i );
293         break;
294      }
295
296   AssertFatal( !mOccluders.contains( object ), "SceneZoneSpace::_removeOccluder - Occluder still added to this zone space!" );
297}
298
299//-----------------------------------------------------------------------------
300
301void SceneZoneSpace::_addOccludersToCullingState( SceneCullingState* state ) const
302{
303   const U32 numOccluders = mOccluders.size();
304   for( U32 i = 0; i < numOccluders; ++ i )
305      state->addOccluder( mOccluders[ i ] );
306}
307
308//-----------------------------------------------------------------------------
309
310void SceneZoneSpace::_traverseConnectedZoneSpaces( SceneTraversalState* state )
311{
312   // Hand the traversal over to all connected zone spaces.
313
314   for( ZoneSpaceRef* ref = mConnectedZoneSpaces; ref != NULL; ref = ref->mNext )
315   {
316      SceneZoneSpace* zoneSpace = ref->mZoneSpace;
317      zoneSpace->traverseZones( state );
318   }
319}
320
321//-----------------------------------------------------------------------------
322
323void SceneZoneSpace::dumpZoneState( bool update )
324{
325   // Nothing to dump if not registered.
326
327   if( !mManager )
328      return;
329
330   // If we should update, trigger rezoning for the space
331   // we occupy.
332
333   if( update )
334      mManager->_rezoneObjects( getWorldBox() );
335
336   Con::printf( "====== Zones in: %s =====", describeSelf().c_str() );
337
338   // Dump connections.
339
340   for( ZoneSpaceRef* ref = mConnectedZoneSpaces; ref != NULL; ref = ref->mNext )
341      Con::printf( "Connected to: %s", ref->mZoneSpace->describeSelf().c_str() );
342
343   // Dump objects.
344
345   for( U32 i = 0; i < getZoneRange(); ++ i )
346   {
347      U32 zoneId = getZoneRangeStart() + i;
348
349      Con::printf( "--- Zone %i", zoneId );
350
351      for( SceneZoneSpaceManager::ZoneContentIterator iter( mManager, zoneId, false ); iter.isValid(); ++ iter )
352         Con::printf( iter->describeSelf() );
353   }
354}
355
356//-----------------------------------------------------------------------------
357
358bool SceneZoneSpace::_setZoneGroup( void* object, const char* index, const char* data )
359{
360   SceneZoneSpace* zone = reinterpret_cast< SceneZoneSpace* >( object );
361   zone->setZoneGroup( EngineUnmarshallData< S32>()( data ) );
362   return false;
363}
364