decalDataFile.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "decalDataFile.h"
  24. #include "math/mathIO.h"
  25. #include "core/tAlgorithm.h"
  26. #include "core/stream/fileStream.h"
  27. #include "T3D/decal/decalManager.h"
  28. #include "T3D/decal/decalData.h"
  29. template<>
  30. void* Resource<DecalDataFile>::create( const Torque::Path &path )
  31. {
  32. FileStream stream;
  33. stream.open( path.getFullPath(), Torque::FS::File::Read );
  34. if ( stream.getStatus() != Stream::Ok )
  35. return NULL;
  36. DecalDataFile *file = new DecalDataFile();
  37. if ( !file->read( stream ) )
  38. {
  39. delete file;
  40. return NULL;
  41. }
  42. return file;
  43. }
  44. template<>
  45. ResourceBase::Signature Resource<DecalDataFile>::signature()
  46. {
  47. return MakeFourCC('d','e','c','f');
  48. }
  49. //-----------------------------------------------------------------------------
  50. DecalDataFile::DecalDataFile()
  51. : mIsDirty( false ),
  52. mSphereWithLastInsertion( NULL )
  53. {
  54. VECTOR_SET_ASSOCIATION( mSphereList );
  55. }
  56. //-----------------------------------------------------------------------------
  57. DecalDataFile::~DecalDataFile()
  58. {
  59. clear();
  60. }
  61. //-----------------------------------------------------------------------------
  62. void DecalDataFile::clear()
  63. {
  64. for ( U32 i=0; i < mSphereList.size(); i++ )
  65. delete mSphereList[i];
  66. mSphereList.clear();
  67. mSphereWithLastInsertion = NULL;
  68. mChunker.freeBlocks();
  69. mIsDirty = true;
  70. }
  71. //-----------------------------------------------------------------------------
  72. bool DecalDataFile::write( Stream& stream )
  73. {
  74. // Write our identifier... so we have a better
  75. // idea if we're reading pure garbage.
  76. // This identifier stands for "Torque Decal Data File".
  77. stream.write( 4, "TDDF" );
  78. // Now the version number.
  79. stream.write( (U8)FILE_VERSION );
  80. Vector<DecalInstance*> allDecals;
  81. // Gather all DecalInstances that should be saved.
  82. for ( U32 i = 0; i < mSphereList.size(); i++ )
  83. {
  84. Vector<DecalInstance*>::const_iterator item = mSphereList[i]->mItems.begin();
  85. for ( ; item != mSphereList[i]->mItems.end(); item++ )
  86. {
  87. if ( (*item)->mFlags & SaveDecal )
  88. allDecals.push_back( (*item) );
  89. }
  90. }
  91. // Gather all the DecalData datablocks used.
  92. Vector<const DecalData*> allDatablocks;
  93. for ( U32 i = 0; i < allDecals.size(); i++ )
  94. allDatablocks.push_back_unique( allDecals[i]->mDataBlock );
  95. // Write out datablock lookupNames.
  96. U32 count = allDatablocks.size();
  97. stream.write( count );
  98. for ( U32 i = 0; i < count; i++ )
  99. stream.write( allDatablocks[i]->lookupName );
  100. Vector<const DecalData*>::iterator dataIter;
  101. // Write out the DecalInstance list.
  102. count = allDecals.size();
  103. stream.write( count );
  104. for ( U32 i = 0; i < count; i++ )
  105. {
  106. DecalInstance *inst = allDecals[i];
  107. dataIter = T3D::find( allDatablocks.begin(), allDatablocks.end(), inst->mDataBlock );
  108. U8 dataIndex = dataIter - allDatablocks.begin();
  109. stream.write( dataIndex );
  110. mathWrite( stream, inst->mPosition );
  111. mathWrite( stream, inst->mNormal );
  112. mathWrite( stream, inst->mTangent );
  113. stream.write( inst->mTextureRectIdx );
  114. stream.write( inst->mSize );
  115. stream.write( inst->mRenderPriority );
  116. }
  117. // Clear the dirty flag.
  118. mIsDirty = false;
  119. return true;
  120. }
  121. //-----------------------------------------------------------------------------
  122. bool DecalDataFile::read( Stream &stream )
  123. {
  124. // NOTE: we are shortcutting by just saving out the DecalInst and
  125. // using regular addDecal methods to add them, which will end up
  126. // generating the DecalSphere(s) in the process.
  127. // It would be more efficient however to just save out all the data
  128. // and read it all in with no calculation required.
  129. // Read our identifier... so we know we're
  130. // not reading in pure garbage.
  131. char id[4] = { 0 };
  132. stream.read( 4, id );
  133. if ( dMemcmp( id, "TDDF", 4 ) != 0 )
  134. {
  135. Con::errorf( "DecalDataFile::read() - This is not a Decal file!" );
  136. return false;
  137. }
  138. // Empty ourselves before we really begin reading.
  139. clear();
  140. // Now the version number.
  141. U8 version;
  142. stream.read( &version );
  143. if ( version != (U8)FILE_VERSION )
  144. {
  145. Con::errorf( "DecalDataFile::read() - file versions do not match!" );
  146. Con::errorf( "You must manually delete the old .decals file before continuing!" );
  147. return false;
  148. }
  149. // Read in the lookupNames of the DecalData datablocks and recover the datablock.
  150. Vector<DecalData*> allDatablocks;
  151. U32 count;
  152. stream.read( &count );
  153. allDatablocks.setSize( count );
  154. for ( U32 i = 0; i < count; i++ )
  155. {
  156. String lookupName;
  157. stream.read( &lookupName );
  158. DecalData *data = DecalData::findDatablock( lookupName );
  159. if ( !data )
  160. {
  161. char name[512];
  162. dSprintf(name, 512, "%s_missing", lookupName.c_str());
  163. DecalData *stubCheck = DecalData::findDatablock( name );
  164. if( !stubCheck )
  165. {
  166. data = new DecalData;
  167. data->lookupName = name;
  168. data->registerObject(name);
  169. Sim::getRootGroup()->addObject( data );
  170. data->mMaterialName = "WarningMaterial";
  171. data->mMaterial = dynamic_cast<Material*>(Sim::findObject("WarningMaterial"));
  172. Con::errorf( "DecalDataFile::read() - DecalData %s does not exist! Temporarily created %s_missing.", lookupName.c_str(), lookupName.c_str());
  173. }
  174. }
  175. allDatablocks[ i ] = data;
  176. }
  177. U8 dataIndex;
  178. DecalData *data;
  179. // Now read all the DecalInstance(s).
  180. stream.read( &count );
  181. for ( U32 i = 0; i < count; i++ )
  182. {
  183. DecalInstance *inst = _allocateInstance();
  184. stream.read( &dataIndex );
  185. mathRead( stream, &inst->mPosition );
  186. mathRead( stream, &inst->mNormal );
  187. mathRead( stream, &inst->mTangent );
  188. stream.read( &inst->mTextureRectIdx );
  189. stream.read( &inst->mSize );
  190. stream.read( &inst->mRenderPriority );
  191. inst->mVisibility = 1.0f;
  192. inst->mFlags = PermanentDecal | SaveDecal | ClipDecal;
  193. inst->mCreateTime = Sim::getCurrentTime();
  194. inst->mVerts = NULL;
  195. inst->mIndices = NULL;
  196. inst->mVertCount = 0;
  197. inst->mIndxCount = 0;
  198. data = allDatablocks[ dataIndex ];
  199. if ( data )
  200. {
  201. inst->mDataBlock = data;
  202. _addDecalToSpheres( inst );
  203. // onload set instances should get added to the appropriate vec
  204. inst->mId = gDecalManager->mDecalInstanceVec.size();
  205. gDecalManager->mDecalInstanceVec.push_back(inst);
  206. }
  207. else
  208. {
  209. _freeInstance( inst );
  210. Con::errorf( "DecalDataFile::read - cannot find DecalData for DecalInstance read from disk." );
  211. }
  212. }
  213. // Clear the dirty flag.
  214. mIsDirty = false;
  215. return true;
  216. }
  217. //-----------------------------------------------------------------------------
  218. DecalInstance* DecalDataFile::addDecal( const Point3F& pos, const Point3F& normal, const Point3F& tangent,
  219. DecalData* decalData, F32 decalScale, S32 decalTexIndex, U8 flags )
  220. {
  221. DecalInstance* newDecal = _allocateInstance();
  222. newDecal->mRenderPriority = 0;
  223. newDecal->mCustomTex = NULL;
  224. newDecal->mId = -1;
  225. newDecal->mPosition = pos;
  226. newDecal->mNormal = normal;
  227. newDecal->mTangent = tangent;
  228. newDecal->mSize = decalData->size * decalScale;
  229. newDecal->mDataBlock = decalData;
  230. S32 frame = newDecal->mDataBlock->frame;
  231. // randomize the frame if the flag is set. this number is used directly below us
  232. // when calculating render coords
  233. if ( decalData->randomize )
  234. frame = gRandGen.randI();
  235. frame %= getMax( decalData->texCoordCount, 0 ) + 1;
  236. newDecal->mTextureRectIdx = frame;
  237. newDecal->mVisibility = 1.0f;
  238. newDecal->mLastAlpha = -1.0f;
  239. newDecal->mCreateTime = Sim::getCurrentTime();
  240. newDecal->mVerts = NULL;
  241. newDecal->mIndices = NULL;
  242. newDecal->mVertCount = 0;
  243. newDecal->mIndxCount = 0;
  244. newDecal->mFlags = flags;
  245. newDecal->mFlags |= ClipDecal;
  246. _addDecalToSpheres( newDecal );
  247. return newDecal;
  248. }
  249. //-----------------------------------------------------------------------------
  250. void DecalDataFile::_addDecalToSpheres( DecalInstance* inst )
  251. {
  252. // First try the sphere we have last inserted an item into, if there is one.
  253. // Given a good spatial locality of insertions, this is a reasonable first
  254. // guess as a good candidate.
  255. if( mSphereWithLastInsertion && mSphereWithLastInsertion->tryAddItem( inst ) )
  256. return;
  257. // Otherwise, go through the list and try to find an existing sphere that meets
  258. // our tolerances.
  259. for( U32 i = 0; i < mSphereList.size(); i++ )
  260. {
  261. DecalSphere* sphere = mSphereList[i];
  262. if( sphere == mSphereWithLastInsertion )
  263. continue;
  264. if( sphere->tryAddItem( inst ) )
  265. {
  266. mSphereWithLastInsertion = sphere;
  267. return;
  268. }
  269. }
  270. // Didn't find a suitable existing sphere, so create a new one.
  271. DecalSphere* sphere = new DecalSphere( inst->mPosition, inst->mSize / 2.f );
  272. mSphereList.push_back( sphere );
  273. mSphereWithLastInsertion = sphere;
  274. sphere->mItems.push_back( inst );
  275. }
  276. //-----------------------------------------------------------------------------
  277. void DecalDataFile::removeDecal( DecalInstance *inst )
  278. {
  279. if( !_removeDecalFromSpheres( inst ) )
  280. return;
  281. _freeInstance( inst );
  282. }
  283. //-----------------------------------------------------------------------------
  284. bool DecalDataFile::_removeDecalFromSpheres( DecalInstance *inst )
  285. {
  286. for( U32 i = 0; i < mSphereList.size(); i++ )
  287. {
  288. DecalSphere* sphere = mSphereList[ i ];
  289. Vector< DecalInstance* > &items = sphere->mItems;
  290. // Try to remove the instance from the list of this sphere.
  291. // If that fails, the instance doesn't belong to this sphere
  292. // so continue.
  293. if( !items.remove( inst ) )
  294. continue;
  295. // If the sphere is now empty, remove it. Otherwise, update
  296. // it's bounds.
  297. if( items.empty() )
  298. {
  299. if( mSphereWithLastInsertion == sphere )
  300. mSphereWithLastInsertion = NULL;
  301. delete sphere;
  302. mSphereList.erase( i );
  303. }
  304. else
  305. sphere->updateWorldSphere();
  306. return true;
  307. }
  308. return false;
  309. }
  310. //-----------------------------------------------------------------------------
  311. void DecalDataFile::notifyDecalModified( DecalInstance *inst )
  312. {
  313. _removeDecalFromSpheres( inst );
  314. _addDecalToSpheres( inst );
  315. }