decalDataFile.cpp
Engine/source/T3D/decal/decalDataFile.cpp
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