Torque3D Documentation / _generateds / decalDataFile.cpp

decalDataFile.cpp

Engine/source/T3D/decal/decalDataFile.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 "decalDataFile.h"
 26
 27#include "math/mathIO.h"
 28#include "core/tAlgorithm.h"
 29#include "core/stream/fileStream.h"
 30
 31#include "T3D/decal/decalManager.h"
 32#include "T3D/decal/decalData.h"
 33
 34
 35template<>
 36void* Resource<DecalDataFile>::create( const Torque::Path &path )
 37{
 38   FileStream stream;
 39   stream.open( path.getFullPath(), Torque::FS::File::Read );
 40   if ( stream.getStatus() != Stream::Ok )
 41      return NULL;
 42
 43   DecalDataFile *file = new DecalDataFile();
 44   if ( !file->read( stream ) )
 45   {
 46      delete file;
 47      return NULL;
 48   }
 49
 50   return file;
 51}
 52
 53template<> 
 54ResourceBase::Signature Resource<DecalDataFile>::signature()
 55{
 56   return MakeFourCC('d','e','c','f');
 57}
 58
 59
 60//-----------------------------------------------------------------------------
 61
 62DecalDataFile::DecalDataFile()
 63   : mIsDirty( false ),
 64     mSphereWithLastInsertion( NULL )
 65{
 66   VECTOR_SET_ASSOCIATION( mSphereList );
 67}
 68
 69//-----------------------------------------------------------------------------
 70
 71DecalDataFile::~DecalDataFile()
 72{
 73   clear();
 74}
 75
 76//-----------------------------------------------------------------------------
 77
 78void DecalDataFile::clear()
 79{
 80   for ( U32 i=0; i < mSphereList.size(); i++ )
 81      delete mSphereList[i];
 82
 83   mSphereList.clear();
 84   mSphereWithLastInsertion = NULL;
 85   mChunker.freeBlocks();
 86
 87   mIsDirty = true;
 88}
 89
 90//-----------------------------------------------------------------------------
 91
 92bool DecalDataFile::write( Stream& stream )
 93{
 94   // Write our identifier... so we have a better
 95   // idea if we're reading pure garbage.
 96   // This identifier stands for "Torque Decal Data File".
 97   stream.write( 4, "TDDF" );
 98
 99   // Now the version number.
100   stream.write( (U8)FILE_VERSION );
101
102   Vector<DecalInstance*> allDecals;
103
104   // Gather all DecalInstances that should be saved.
105   for ( U32 i = 0; i < mSphereList.size(); i++ )  
106   {      
107      Vector<DecalInstance*>::const_iterator item = mSphereList[i]->mItems.begin();
108      for ( ; item != mSphereList[i]->mItems.end(); item++ )
109      {
110         if ( (*item)->mFlags & SaveDecal )
111            allDecals.push_back( (*item) );
112      }
113   }
114
115   // Gather all the DecalData datablocks used.
116   Vector<const DecalData*> allDatablocks;
117   for ( U32 i = 0; i < allDecals.size(); i++ )
118      allDatablocks.push_back_unique( allDecals[i]->mDataBlock );
119
120   // Write out datablock lookupNames.
121   U32 count = allDatablocks.size();
122   stream.write( count );
123   for ( U32 i = 0; i < count; i++ )
124      stream.write( allDatablocks[i]->lookupName );
125
126   Vector<const DecalData*>::iterator dataIter;
127
128   // Write out the DecalInstance list.
129   count = allDecals.size();
130   stream.write( count );
131   for ( U32 i = 0; i < count; i++ )
132   {
133      DecalInstance *inst = allDecals[i];
134
135      dataIter = T3D::find( allDatablocks.begin(), allDatablocks.end(), inst->mDataBlock );
136      U8 dataIndex = dataIter - allDatablocks.begin();
137      
138      stream.write( dataIndex );
139      mathWrite( stream, inst->mPosition );
140      mathWrite( stream, inst->mNormal );
141      mathWrite( stream, inst->mTangent );
142      stream.write( inst->mTextureRectIdx );   
143      stream.write( inst->mSize );
144      stream.write( inst->mRenderPriority );
145   }
146
147   // Clear the dirty flag.
148   mIsDirty = false;
149
150   return true;
151}
152
153//-----------------------------------------------------------------------------
154
155bool DecalDataFile::read( Stream &stream )
156{
157   // NOTE: we are shortcutting by just saving out the DecalInst and 
158   // using regular addDecal methods to add them, which will end up
159   // generating the DecalSphere(s) in the process.
160   // It would be more efficient however to just save out all the data
161   // and read it all in with no calculation required.
162
163   // Read our identifier... so we know we're 
164   // not reading in pure garbage.
165   char id[4] = { 0 };
166   stream.read( 4, id );
167   if ( dMemcmp( id, "TDDF", 4 ) != 0 )
168   {
169      Con::errorf( "DecalDataFile::read() - This is not a Decal file!" );
170      return false;
171   }
172
173   // Empty ourselves before we really begin reading.
174   clear();
175
176   // Now the version number.
177   U8 version;
178   stream.read( &version );
179   if ( version != (U8)FILE_VERSION )
180   {
181      Con::errorf( "DecalDataFile::read() - file versions do not match!" );
182      Con::errorf( "You must manually delete the old .decals file before continuing!" );
183      return false;
184   }
185
186   // Read in the lookupNames of the DecalData datablocks and recover the datablock.   
187   Vector<DecalData*> allDatablocks;
188   U32 count;
189   stream.read( &count );
190   allDatablocks.setSize( count );
191   for ( U32 i = 0; i < count; i++ )
192   {      
193      String lookupName;      
194      stream.read( &lookupName );
195      
196      DecalData *data = DecalData::findDatablock( lookupName );
197
198      if ( !data )
199      {
200         char name[512];
201         dSprintf(name, 512, "%s_missing", lookupName.c_str());
202
203         DecalData *stubCheck = DecalData::findDatablock( name );
204         if( !stubCheck )
205         {
206            data = new DecalData;
207            data->lookupName = name;
208            data->registerObject(name);
209            Sim::getRootGroup()->addObject( data );
210            data->materialName = "WarningMaterial";
211            data->material = dynamic_cast<Material*>(Sim::findObject("WarningMaterial"));
212         
213            Con::errorf( "DecalDataFile::read() - DecalData %s does not exist! Temporarily created %s_missing.", lookupName.c_str(), lookupName.c_str());
214         }
215      }
216      
217      allDatablocks[ i ] = data;
218   }
219
220   U8 dataIndex;   
221   DecalData *data;
222
223   // Now read all the DecalInstance(s).
224   stream.read( &count );
225   for ( U32 i = 0; i < count; i++ )
226   {           
227      DecalInstance *inst = _allocateInstance();
228
229      stream.read( &dataIndex );
230      mathRead( stream, &inst->mPosition );
231      mathRead( stream, &inst->mNormal );
232      mathRead( stream, &inst->mTangent );
233      stream.read( &inst->mTextureRectIdx );
234      stream.read( &inst->mSize );
235      stream.read( &inst->mRenderPriority );
236
237      inst->mVisibility = 1.0f;
238      inst->mFlags = PermanentDecal | SaveDecal | ClipDecal;
239      inst->mCreateTime = Sim::getCurrentTime();
240      inst->mVerts = NULL;
241      inst->mIndices = NULL;
242      inst->mVertCount = 0;
243      inst->mIndxCount = 0;
244
245      data = allDatablocks[ dataIndex ];
246
247      if ( data )          
248      {         
249         inst->mDataBlock = data;
250
251         _addDecalToSpheres( inst );
252         
253         // onload set instances should get added to the appropriate vec
254         inst->mId = gDecalManager->mDecalInstanceVec.size();
255         gDecalManager->mDecalInstanceVec.push_back(inst);
256      }
257      else
258      {
259         _freeInstance( inst );
260         Con::errorf( "DecalDataFile::read - cannot find DecalData for DecalInstance read from disk." );
261      }
262   }
263
264   // Clear the dirty flag.
265   mIsDirty = false;
266
267   return true;
268}
269
270//-----------------------------------------------------------------------------
271
272DecalInstance* DecalDataFile::addDecal( const Point3F& pos, const Point3F& normal, const Point3F& tangent,
273                                        DecalData* decalData, F32 decalScale, S32 decalTexIndex, U8 flags )
274{
275   DecalInstance* newDecal = _allocateInstance();
276
277   newDecal->mRenderPriority = 0;
278   newDecal->mCustomTex = NULL;
279   newDecal->mId = -1;
280
281   newDecal->mPosition = pos;
282   newDecal->mNormal = normal;
283   newDecal->mTangent = tangent;
284
285   newDecal->mSize = decalData->size * decalScale;
286
287   newDecal->mDataBlock = decalData;
288
289   S32 frame = newDecal->mDataBlock->frame;
290   // randomize the frame if the flag is set. this number is used directly below us
291   // when calculating render coords
292   if ( decalData->randomize )
293      frame = gRandGen.randI();
294
295   frame %= getMax( decalData->texCoordCount, 0 ) + 1;
296
297   newDecal->mTextureRectIdx = frame;
298
299   newDecal->mVisibility = 1.0f;
300
301   newDecal->mLastAlpha = -1.0f;
302
303   newDecal->mCreateTime = Sim::getCurrentTime();
304
305   newDecal->mVerts = NULL;
306   newDecal->mIndices = NULL;
307   newDecal->mVertCount = 0;
308   newDecal->mIndxCount = 0;
309
310   newDecal->mFlags = flags;
311   newDecal->mFlags |= ClipDecal;
312
313   _addDecalToSpheres( newDecal );
314
315   return newDecal;
316}
317
318//-----------------------------------------------------------------------------
319
320void DecalDataFile::_addDecalToSpheres( DecalInstance* inst )
321{
322   // First try the sphere we have last inserted an item into, if there is one.
323   // Given a good spatial locality of insertions, this is a reasonable first
324   // guess as a good candidate.
325
326   if( mSphereWithLastInsertion && mSphereWithLastInsertion->tryAddItem( inst ) )
327      return;
328
329   // Otherwise, go through the list and try to find an existing sphere that meets
330   // our tolerances.
331
332   for( U32 i = 0; i < mSphereList.size(); i++ )
333   {
334      DecalSphere* sphere = mSphereList[i];
335      
336      if( sphere == mSphereWithLastInsertion )
337         continue;
338
339      if( sphere->tryAddItem( inst ) )
340      {
341         mSphereWithLastInsertion = sphere;
342         return;
343      }
344   }
345
346   // Didn't find a suitable existing sphere, so create a new one.
347
348   DecalSphere* sphere = new DecalSphere( inst->mPosition, inst->mSize / 2.f );
349
350   mSphereList.push_back( sphere );
351   mSphereWithLastInsertion = sphere;
352
353   sphere->mItems.push_back( inst );
354}
355
356//-----------------------------------------------------------------------------
357
358void DecalDataFile::removeDecal( DecalInstance *inst )
359{
360   if( !_removeDecalFromSpheres( inst ) )
361      return;
362
363   _freeInstance( inst );
364}
365
366//-----------------------------------------------------------------------------
367
368bool DecalDataFile::_removeDecalFromSpheres( DecalInstance *inst )
369{
370   for( U32 i = 0; i < mSphereList.size(); i++ )
371   {
372      DecalSphere* sphere = mSphereList[ i ];
373      Vector< DecalInstance*> &items = sphere->mItems;
374
375      // Try to remove the instance from the list of this sphere.
376      // If that fails, the instance doesn't belong to this sphere
377      // so continue.
378
379      if( !items.remove( inst ) )
380         continue;
381
382      // If the sphere is now empty, remove it.  Otherwise, update
383      // it's bounds.
384
385      if( items.empty() )
386      {
387         if( mSphereWithLastInsertion == sphere )
388            mSphereWithLastInsertion = NULL;
389
390         delete sphere;      
391         mSphereList.erase( i );
392      }
393      else
394         sphere->updateWorldSphere();
395
396      return true;
397   }
398
399   return false;
400}
401
402//-----------------------------------------------------------------------------
403
404void DecalDataFile::notifyDecalModified( DecalInstance *inst )
405{
406   _removeDecalFromSpheres( inst );
407   _addDecalToSpheres( inst );
408}
409