afxModel.cpp
Engine/source/afx/ce/afxModel.cpp
Public Defines
define
BAD_ANIM_ID() 999999999
define
myOffset(field) (field, )
Public Functions
ConsoleDocClass(afxModel , "@brief A Model effect as defined by an <a href="/coding/class/structafxmodeldata/">afxModelData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablock.\n\n</a>" "A Model effect is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lightweight client-only geometry object useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> effect-driven " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">props.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
ConsoleDocClass(afxModelData , "@brief A datablock that specifies <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Model <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "A Model effect is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lightweight client-only geometry object useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> effect-driven props." "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
Detailed Description
Public Defines
BAD_ANIM_ID() 999999999
myOffset(field) (field, )
Public Functions
ConsoleDocClass(afxModel , "@brief A Model effect as defined by an <a href="/coding/class/structafxmodeldata/">afxModelData</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">datablock.\n\n</a>" "A Model effect is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lightweight client-only geometry object useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> effect-driven " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">props.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" )
ConsoleDocClass(afxModelData , "@brief A datablock that specifies <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> Model <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n\n</a>" "A Model effect is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lightweight client-only geometry object useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> effect-driven props." "\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">afxEffects\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">AFX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Datablocks\n</a>" )
IMPLEMENT_CO_DATABLOCK_V1(afxModelData )
IMPLEMENT_CO_NETOBJECT_V1(afxModel )
1 2 3//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 4// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 5// Copyright (C) 2015 Faust Logic, Inc. 6// 7// Permission is hereby granted, free of charge, to any person obtaining a copy 8// of this software and associated documentation files (the "Software"), to 9// deal in the Software without restriction, including without limitation the 10// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11// sell copies of the Software, and to permit persons to whom the Software is 12// furnished to do so, subject to the following conditions: 13// 14// The above copyright notice and this permission notice shall be included in 15// all copies or substantial portions of the Software. 16// 17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23// IN THE SOFTWARE. 24// 25//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 26 27#include "afx/arcaneFX.h" 28 29#include "T3D/objectTypes.h" 30#include "T3D/gameBase/gameProcess.h" 31#include "core/resourceManager.h" 32#include "sim/netConnection.h" 33#include "scene/sceneRenderState.h" 34#include "scene/sceneManager.h" 35#include "ts/tsShapeInstance.h" 36#include "ts/tsMaterialList.h" 37 38#include "afx/ce/afxModel.h" 39 40//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 41// afxModelData 42 43IMPLEMENT_CO_DATABLOCK_V1(afxModelData); 44 45ConsoleDocClass( afxModelData, 46 "@brief A datablock that specifies a Model effect.\n\n" 47 48 "A Model effect is a lightweight client-only geometry object useful for effect-driven props." 49 "\n\n" 50 51 "@ingroup afxEffects\n" 52 "@ingroup AFX\n" 53 "@ingroup Datablocks\n" 54); 55 56afxModelData::afxModelData() 57{ 58 shapeName = ST_NULLSTRING; 59 sequence = ST_NULLSTRING; 60 seq_rate = 1.0f; 61 seq_offset = 0.0f; 62 alpha_mult = 1.0f; 63 use_vertex_alpha = false; 64 force_on_material_flags = 0; 65 force_off_material_flags = 0; 66 texture_filtering = true; 67 fog_mult = 1.0f; 68 remap_txr_tags = ST_NULLSTRING; 69 remap_buffer = 0; 70 71 overrideLightingOptions = false; 72 receiveSunLight = true; 73 receiveLMLighting = true; 74 useAdaptiveSelfIllumination = false; 75 useCustomAmbientLighting = false; 76 customAmbientForSelfIllumination = false; 77 customAmbientLighting = LinearColorF(0.0f, 0.0f, 0.0f); 78 shadowEnable = false; 79 80 shadowSize = 128; 81 shadowMaxVisibleDistance = 80.0f; 82 shadowProjectionDistance = 10.0f; 83 shadowSphereAdjust = 1.0; 84} 85 86afxModelData::afxModelData(const afxModelData& other, bool temp_clone) : GameBaseData(other, temp_clone) 87{ 88 shapeName = other.shapeName; 89 shape = other.shape; // -- 90 sequence = other.sequence; 91 seq_rate = other.seq_rate; 92 seq_offset = other.seq_offset; 93 alpha_mult = other.alpha_mult; 94 use_vertex_alpha = other.use_vertex_alpha; 95 force_on_material_flags = other.force_on_material_flags; 96 force_off_material_flags = other.force_off_material_flags; 97 texture_filtering = other.texture_filtering; 98 fog_mult = other.fog_mult; 99 remap_txr_tags = other.remap_txr_tags; 100 remap_buffer = other.remap_buffer; 101 overrideLightingOptions = other.overrideLightingOptions; 102 receiveSunLight = other.receiveSunLight; 103 receiveLMLighting = other.receiveLMLighting; 104 useAdaptiveSelfIllumination = other.useAdaptiveSelfIllumination; 105 useCustomAmbientLighting = other.useCustomAmbientLighting; 106 customAmbientForSelfIllumination = other.customAmbientForSelfIllumination; 107 customAmbientLighting = other.customAmbientLighting; 108 shadowEnable = other.shadowEnable; 109 110 shadowSize = other.shadowSize; 111 shadowMaxVisibleDistance = other.shadowMaxVisibleDistance; 112 shadowProjectionDistance = other.shadowProjectionDistance; 113 shadowSphereAdjust = other.shadowSphereAdjust; 114} 115 116afxModelData::~afxModelData() 117{ 118 if (remap_buffer) 119 dFree(remap_buffer); 120} 121 122bool afxModelData::preload(bool server, String &errorStr) 123{ 124 if (Parent::preload(server, errorStr) == false) 125 return false; 126 127 // don't need to do this stuff on the server 128 if (server) 129 return true; 130 131 if (shapeName != ST_NULLSTRING && !shape) 132 { 133 shape = ResourceManager::get().load(shapeName); 134 if (!shape) 135 { 136 errorStr = String::ToString("afxModelData::load: Failed to load shape \"%s\"", shapeName); 137 return false; 138 } 139 140 // just parse up the string and collect the remappings in txr_tag_remappings. 141 if (remap_txr_tags != ST_NULLSTRING) 142 { 143 txr_tag_remappings.clear(); 144 if (remap_buffer) 145 dFree(remap_buffer); 146 147 remap_buffer = dStrdup(remap_txr_tags); 148 149 char* remap_token = dStrtok(remap_buffer, " \t"); 150 while (remap_token != NULL) 151 { 152 char* colon = dStrchr(remap_token, ':'); 153 if (colon) 154 { 155 *colon = '\0'; 156 txr_tag_remappings.increment(); 157 txr_tag_remappings.last().old_tag = remap_token; 158 txr_tag_remappings.last().new_tag = colon+1; 159 } 160 remap_token = dStrtok(NULL, " \t"); 161 } 162 } 163 164 // this little hack messes things up when remapping texture tags 165 if (txr_tag_remappings.size() == 0) 166 { 167 // this little hack forces the textures to preload 168 TSShapeInstance* pDummy = new TSShapeInstance(shape); 169 delete pDummy; 170 } 171 } 172 173 return true; 174} 175 176#define myOffset(field) Offset(field, afxModelData) 177 178void afxModelData::initPersistFields() 179{ 180 addField("shapeFile", TypeFilename, myOffset(shapeName), 181 "The name of a .dts format file to use for the model."); 182 addField("sequence", TypeFilename, myOffset(sequence), 183 "The name of an animation sequence to play in the model."); 184 addField("sequenceRate", TypeF32, myOffset(seq_rate), 185 "The rate of playback for the sequence."); 186 addField("sequenceOffset", TypeF32, myOffset(seq_offset), 187 "An offset in seconds indicating a starting point for the animation sequence " 188 "specified by the sequence field. A rate of 1.0 (rather than sequenceRate) is used " 189 "to convert from seconds to the thread offset."); 190 addField("alphaMult", TypeF32, myOffset(alpha_mult), 191 "An alpha multiplier used to set maximum opacity of the model."); 192 193 addField("fogMult", TypeF32, myOffset(fog_mult), 194 ""); 195 addField("remapTextureTags", TypeString, myOffset(remap_txr_tags), 196 "Rename one or more texture tags in the model. Texture tags are what link a " 197 "model's textures to materials.\n" 198 "Field should be a string containing space-separated remapping tokens. A remapping " 199 "token is two names separated by a colon, ':'. The first name should be a texture-tag " 200 "that exists in the model, while the second is a new name to replace it. The string " 201 "can have any number of remapping tokens as long as the total string length does not " 202 "exceed 255."); 203 addField("shadowEnable", TypeBool, myOffset(shadowEnable), 204 "Sets whether the model casts a shadow."); 205 206 addField("useVertexAlpha", TypeBool, myOffset(use_vertex_alpha), 207 "deprecated"); 208 addField("forceOnMaterialFlags", TypeS32, myOffset(force_on_material_flags), 209 "deprecated"); 210 addField("forceOffMaterialFlags", TypeS32, myOffset(force_off_material_flags), 211 "deprecated"); 212 addField("textureFiltering", TypeBool, myOffset(texture_filtering), 213 "deprecated"); 214 addField("overrideLightingOptions", TypeBool, myOffset(overrideLightingOptions), 215 "deprecated"); 216 addField("receiveSunLight", TypeBool, myOffset(receiveSunLight), 217 ""); 218 addField("receiveLMLighting", TypeBool, myOffset(receiveLMLighting), 219 "deprecated"); 220 addField("useAdaptiveSelfIllumination", TypeBool, myOffset(useAdaptiveSelfIllumination), 221 "deprecated"); 222 addField("useCustomAmbientLighting", TypeBool, myOffset(useCustomAmbientLighting), 223 "deprecated"); 224 addField("customAmbientSelfIllumination", TypeBool, myOffset(customAmbientForSelfIllumination), 225 "deprecated"); 226 addField("customAmbientLighting", TypeColorF, myOffset(customAmbientLighting), 227 "deprecated"); 228 addField("shadowSize", TypeS32, myOffset(shadowSize), 229 "deprecated"); 230 addField("shadowMaxVisibleDistance", TypeF32, myOffset(shadowMaxVisibleDistance), 231 "deprecated"); 232 addField("shadowProjectionDistance", TypeF32, myOffset(shadowProjectionDistance), 233 "deprecated"); 234 addField("shadowSphereAdjust", TypeF32, myOffset(shadowSphereAdjust), 235 "deprecated"); 236 237 Parent::initPersistFields(); 238 239 // Material Flags 240 Con::setIntVariable("$MaterialFlags::S_Wrap", TSMaterialList::S_Wrap); 241 Con::setIntVariable("$MaterialFlags::T_Wrap", TSMaterialList::T_Wrap); 242 Con::setIntVariable("$MaterialFlags::Translucent", TSMaterialList::Translucent); 243 Con::setIntVariable("$MaterialFlags::Additive", TSMaterialList::Additive); 244 Con::setIntVariable("$MaterialFlags::Subtractive", TSMaterialList::Subtractive); 245 Con::setIntVariable("$MaterialFlags::SelfIlluminating", TSMaterialList::SelfIlluminating); 246 Con::setIntVariable("$MaterialFlags::NeverEnvMap", TSMaterialList::NeverEnvMap); 247 Con::setIntVariable("$MaterialFlags::NoMipMap", TSMaterialList::NoMipMap); 248 Con::setIntVariable("$MaterialFlags::MipMap_ZeroBorder", TSMaterialList::MipMap_ZeroBorder); 249 Con::setIntVariable("$MaterialFlags::AuxiliaryMap", TSMaterialList::AuxiliaryMap); 250 251#if defined(AFX_CAP_AFXMODEL_TYPE) 252 Con::setIntVariable("$TypeMasks::afxModelObjectType", afxModelObjectType); 253#endif 254} 255 256void afxModelData::packData(BitStream* stream) 257{ 258 Parent::packData(stream); 259 260 stream->writeString(shapeName); 261 stream->writeString(sequence); 262 stream->write(seq_rate); 263 stream->write(seq_offset); 264 stream->write(alpha_mult); 265 stream->write(use_vertex_alpha); 266 stream->write(force_on_material_flags); 267 stream->write(force_off_material_flags); 268 stream->writeFlag(texture_filtering); 269 stream->write(fog_mult); 270 271 stream->writeString(remap_txr_tags); 272 273 stream->writeFlag(overrideLightingOptions); 274 stream->writeFlag(receiveSunLight); 275 stream->writeFlag(useAdaptiveSelfIllumination); 276 stream->writeFlag(useCustomAmbientLighting); 277 stream->writeFlag(customAmbientForSelfIllumination); 278 stream->write(customAmbientLighting); 279 stream->writeFlag(receiveLMLighting); 280 stream->writeFlag(shadowEnable); 281 282 stream->write(shadowSize); 283 stream->write(shadowMaxVisibleDistance); 284 stream->write(shadowProjectionDistance); 285 stream->write(shadowSphereAdjust); 286} 287 288void afxModelData::unpackData(BitStream* stream) 289{ 290 Parent::unpackData(stream); 291 292 shapeName = stream->readSTString(); 293 sequence = stream->readSTString(); 294 stream->read(&seq_rate); 295 stream->read(&seq_offset); 296 stream->read(&alpha_mult); 297 stream->read(&use_vertex_alpha); 298 stream->read(&force_on_material_flags); 299 stream->read(&force_off_material_flags); 300 texture_filtering = stream->readFlag(); 301 stream->read(&fog_mult); 302 303 remap_txr_tags = stream->readSTString(); 304 305 overrideLightingOptions = stream->readFlag(); 306 receiveSunLight = stream->readFlag(); 307 useAdaptiveSelfIllumination = stream->readFlag(); 308 useCustomAmbientLighting = stream->readFlag(); 309 customAmbientForSelfIllumination = stream->readFlag(); 310 stream->read(&customAmbientLighting); 311 receiveLMLighting = stream->readFlag(); 312 shadowEnable = stream->readFlag(); 313 314 stream->read(&shadowSize); 315 stream->read(&shadowMaxVisibleDistance); 316 stream->read(&shadowProjectionDistance); 317 stream->read(&shadowSphereAdjust); 318} 319 320void afxModelData::onPerformSubstitutions() 321{ 322 if (shapeName != ST_NULLSTRING) 323 { 324 shape = ResourceManager::get().load(shapeName); 325 if (!shape) 326 { 327 Con::errorf("afxModelData::onPerformSubstitutions: Failed to load shape \"%s\"", shapeName); 328 return; 329 } 330 331 // REMAP-TEXTURE-TAGS ISSUES? 332 } 333} 334 335//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 336//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 337// afxModel 338 339IMPLEMENT_CO_NETOBJECT_V1(afxModel); 340 341ConsoleDocClass( afxModel, 342 "@brief A Model effect as defined by an afxModelData datablock.\n\n" 343 344 "A Model effect is a lightweight client-only geometry object useful for effect-driven " 345 "props.\n" 346 347 "@ingroup afxEffects\n" 348 "@ingroup AFX\n" 349); 350 351afxModel::afxModel() 352{ 353 mTypeMask |= DynamicShapeObjectType; 354#if defined(AFX_CAP_AFXMODEL_TYPE) 355 mTypeMask |= afxModelObjectType; 356#endif 357 358 shape_inst = 0; 359 360 main_seq_thread = 0; 361 main_seq_id = -1; 362 seq_rate_factor = 1.0f; 363 last_anim_tag = 0; 364 365 seq_animates_vis = false; 366 fade_amt = 1.0f; 367 is_visible = true; 368 sort_priority = 0; 369 mDataBlock = NULL; 370 mNetFlags.set( IsGhost ); 371} 372 373afxModel::~afxModel() 374{ 375 delete shape_inst; 376} 377 378void afxModel::setSequenceRateFactor(F32 factor) 379{ 380 seq_rate_factor = factor; 381 if (shape_inst != NULL && main_seq_thread != NULL) 382 shape_inst->setTimeScale(main_seq_thread, seq_rate_factor*mDataBlock->seq_rate); 383} 384 385//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 386 387bool afxModel::onNewDataBlock(GameBaseData* dptr, bool reload) 388{ 389 mDataBlock = dynamic_cast<afxModelData*>(dptr); 390 if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload)) 391 return false; 392 393 return true; 394} 395 396bool afxModel::onAdd() 397{ 398 // first check if we have a server connection, if we don't then this is on the server 399 // and we should exit, then check if the parent fails to add the object 400 NetConnection* conn = NetConnection::getConnectionToServer(); 401 if (!conn || !Parent::onAdd()) 402 return false; 403 404 // setup our bounding box 405 if (mDataBlock->shape) 406 mObjBox = mDataBlock->shape->mBounds; 407 else 408 mObjBox = Box3F(Point3F(-1, -1, -1), Point3F(1, 1, 1)); 409 410 // setup the shape instance and sequence 411 if (mDataBlock->shape) 412 { 413 if (/*isClientObject() && */mDataBlock->txr_tag_remappings.size() > 0) 414 { 415 // temporarily substitute material tags with alternates 416 TSMaterialList* mat_list = mDataBlock->shape->materialList; 417 if (mat_list) 418 { 419 for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) 420 { 421 afxModelData::TextureTagRemapping* remap = &mDataBlock->txr_tag_remappings[i]; 422 Vector<String> & mat_names = (Vector<String>&) mat_list->getMaterialNameList(); 423 for (S32 j = 0; j < mat_names.size(); j++) 424 { 425 if (mat_names[j].compare(remap->old_tag, dStrlen(remap->old_tag), String::NoCase) == 0) 426 { 427 //Con::printf("REMAP TEXTURE TAG [%s] TO [%s]", remap->old_tag, remap->new_tag); 428 mat_names[j] = String(remap->new_tag); 429 mat_names[j].insert(0,'#'); 430 break; 431 } 432 } 433 } 434 } 435 } 436 437 shape_inst = new TSShapeInstance(mDataBlock->shape); 438 439 if (true) // isClientObject()) 440 { 441 shape_inst->cloneMaterialList(); 442 443 // restore the material tags to original form 444 if (mDataBlock->txr_tag_remappings.size() > 0) 445 { 446 TSMaterialList* mat_list = mDataBlock->shape->materialList; 447 if (mat_list) 448 { 449 for (S32 i = 0; i < mDataBlock->txr_tag_remappings.size(); i++) 450 { 451 afxModelData::TextureTagRemapping* remap = &mDataBlock->txr_tag_remappings[i]; 452 Vector<String> & mat_names = (Vector<String>&) mat_list->getMaterialNameList(); 453 for (S32 j = 0; j < mat_names.size(); j++) 454 { 455 if (mat_names[j].compare(remap->new_tag, dStrlen(remap->new_tag)) == 0) 456 { 457 //Con::printf("UNREMAP TEXTURE TAG [%s] TO [%s]", remap->new_tag, remap->old_tag); 458 mat_names[j] = String(remap->old_tag); 459 break; 460 } 461 } 462 } 463 } 464 } 465 } 466 467 if (mDataBlock->sequence == ST_NULLSTRING) 468 { 469 main_seq_thread = 0; 470 main_seq_id = -1; 471 } 472 else 473 { 474 // here we start the default animation sequence 475 TSShape* shape = shape_inst->getShape(); 476 main_seq_id = shape->findSequence(mDataBlock->sequence); 477 if (main_seq_id != -1) 478 { 479 main_seq_thread = shape_inst->addThread(); 480 481 F32 seq_pos = 0.0f; 482 if (mDataBlock->seq_offset > 0.0f && mDataBlock->seq_offset < shape_inst->getDuration(main_seq_thread)) 483 seq_pos = mDataBlock->seq_offset / shape_inst->getDuration(main_seq_thread); 484 485 shape_inst->setTimeScale(main_seq_thread, seq_rate_factor*mDataBlock->seq_rate); 486 shape_inst->setSequence(main_seq_thread, main_seq_id, seq_pos); 487 seq_animates_vis = shape->sequences[main_seq_id].visMatters.testAll(); 488 } 489 } 490 491 // deal with material changes 492 if (shape_inst && (mDataBlock->force_on_material_flags | mDataBlock->force_off_material_flags)) 493 { 494 shape_inst->cloneMaterialList(); 495 TSMaterialList* mats = shape_inst->getMaterialList(); 496 if (mDataBlock->force_on_material_flags != 0) 497 { 498 for (U32 i = 0; i < mats->size(); i++) 499 mats->setFlags(i, mats->getFlags(i) | mDataBlock->force_on_material_flags); 500 } 501 502 if (mDataBlock->force_off_material_flags != 0) 503 { 504 for (U32 i = 0; i < mats->size(); i++) 505 mats->setFlags(i, mats->getFlags(i) & ~mDataBlock->force_off_material_flags); 506 } 507 } 508 } 509 510 resetWorldBox(); 511 512 if (mDataBlock->shape) 513 { 514 // Scan out the collision hulls... 515 static const String sCollisionStr( "collision-" ); 516 517 for (U32 i = 0; i < mDataBlock->shape->details.size(); i++) 518 { 519 const String &name = mDataBlock->shape->names[mDataBlock->shape->details[i].nameIndex]; 520 521 if (name.compare( sCollisionStr, sCollisionStr.length(), String::NoCase ) == 0) 522 { 523 mCollisionDetails.push_back(i); 524 525 // The way LOS works is that it will check to see if there is a LOS detail that matches 526 // the the collision detail + 1 + MaxCollisionShapes (this variable name should change in 527 // the future). If it can't find a matching LOS it will simply use the collision instead. 528 // We check for any "unmatched" LOS's further down 529 mLOSDetails.increment(); 530 531 char buff[128]; 532 dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + 8/*MaxCollisionShapes*/); 533 U32 los = mDataBlock->shape->findDetail(buff); 534 if (los == -1) 535 mLOSDetails.last() = i; 536 else 537 mLOSDetails.last() = los; 538 } 539 } 540 541 // Snag any "unmatched" LOS details 542 static const String sLOSStr( "LOS-" ); 543 544 for (U32 i = 0; i < mDataBlock->shape->details.size(); i++) 545 { 546 const String &name = mDataBlock->shape->names[mDataBlock->shape->details[i].nameIndex]; 547 548 if (name.compare( sLOSStr, sLOSStr.length(), String::NoCase ) == 0) 549 { 550 // See if we already have this LOS 551 bool found = false; 552 for (U32 j = 0; j < mLOSDetails.size(); j++) 553 { 554 if (mLOSDetails[j] == i) 555 { 556 found = true; 557 break; 558 } 559 } 560 561 if (!found) 562 mLOSDetails.push_back(i); 563 } 564 } 565 566 // Compute the hull accelerators (actually, just force the shape to compute them) 567 for (U32 i = 0; i < mCollisionDetails.size(); i++) 568 shape_inst->getShape()->getAccelerator(mCollisionDetails[i]); 569 } 570 571 // tell engine the model exists 572 gClientSceneGraph->addObjectToScene(this); 573 removeFromProcessList(); 574 ClientProcessList::get()->addObject(this); 575 conn->addObject(this); 576 577 return true; 578} 579 580void afxModel::onRemove() 581{ 582 mSceneManager->removeObjectFromScene(this); 583 getContainer()->removeObject(this); 584 Parent::onRemove(); 585} 586 587//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 588 589void afxModel::advanceTime(F32 dt) 590{ 591 if (main_seq_thread) 592 shape_inst->advanceTime(dt, main_seq_thread); 593 594 for (S32 i = 0; i < blend_clips.size(); i++) 595 shape_inst->advanceTime(dt, blend_clips[i].thread); 596} 597 598//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~// 599 600void afxModel::prepRenderImage(SceneRenderState* state) 601{ 602 if (!is_visible || !shape_inst) 603 return; 604 605 // calculate distance to camera 606 Point3F cameraOffset; 607 getRenderTransform().getColumn(3, &cameraOffset); 608 cameraOffset -= state->getCameraPosition(); 609 F32 dist = cameraOffset.len(); 610 if (dist < 0.01f) 611 dist = 0.01f; 612 613 F32 invScale = (1.0f/getMax(getMax(mObjScale.x,mObjScale.y),mObjScale.z)); 614 shape_inst->setDetailFromDistance(state, dist*invScale); 615 if ( shape_inst->getCurrentDetail() < 0 ) 616 return; 617 618 renderObject(state); 619} 620 621bool afxModel::castRay(const Point3F &start, const Point3F &end, RayInfo* info) 622{ 623 if (shape_inst) 624 { 625 RayInfo shortest; 626 shortest.t = 1e8; 627 628 info->object = NULL; 629 if (mLOSDetails.size() > 0) 630 { 631 for (U32 i = 0; i < mLOSDetails.size(); i++) 632 { 633 shape_inst->animate(mLOSDetails[i]); 634 if (shape_inst->castRay(start, end, info, mLOSDetails[i])) 635 { 636 info->object = this; 637 if (info->t < shortest.t) 638 shortest = *info; 639 } 640 } 641 } 642 else 643 { 644 if (mCollisionDetails.size() > 0) 645 { 646 for (U32 i = 0; i < mCollisionDetails.size(); i++) 647 { 648 shape_inst->animate(mCollisionDetails[i]); 649 if (shape_inst->castRay(start, end, info, mCollisionDetails[i])) 650 { 651 info->object = this; 652 if (info->t < shortest.t) 653 shortest = *info; 654 } 655 } 656 } 657 } 658 659 if (info->object == this) 660 { 661 // Copy out the shortest time... 662 *info = shortest; 663 return true; 664 } 665 } 666 667 return false; 668} 669 670U32 afxModel::unique_anim_tag_counter = 1; 671#define BAD_ANIM_ID 999999999 672 673U32 afxModel::setAnimClip(const char* clip, F32 pos, F32 rate, F32 trans) 674{ 675 if (!shape_inst) 676 return 0; 677 678 TSShape* shape = shape_inst->getShape(); 679 680 S32 seq_id = shape->findSequence(clip); 681 if (seq_id == -1) 682 { 683 Con::errorf("afxModel::setAnimClip() -- failed to find a sequence matching the name, \"%s\".", clip); 684 return 0; 685 } 686 687 // JTF Note: test if this blend implementation is working 688 if (shape->sequences[seq_id].isBlend()) 689 { 690 BlendThread blend_clip; 691 blend_clip.tag = ((unique_anim_tag_counter++) | 0x80000000); 692 693 blend_clip.thread = shape_inst->addThread(); 694 shape_inst->setSequence(blend_clip.thread, seq_id, pos); 695 shape_inst->setTimeScale(blend_clip.thread, rate); 696 697 blend_clips.push_back(blend_clip); 698 699 return blend_clip.tag; 700 } 701 702 if (!main_seq_thread) 703 { 704 main_seq_thread = shape_inst->addThread(); 705 shape_inst->setTimeScale(main_seq_thread, seq_rate_factor*rate); 706 shape_inst->setSequence(main_seq_thread, seq_id, pos); 707 seq_animates_vis = shape->sequences[seq_id].visMatters.testAll(); 708 } 709 else 710 { 711 shape_inst->setTimeScale(main_seq_thread, seq_rate_factor*rate); 712 713 F32 transTime = (trans < 0) ? 0.25 : trans; 714 if (transTime > 0.0f) 715 shape_inst->transitionToSequence(main_seq_thread, seq_id, pos, transTime, true); 716 else 717 shape_inst->setSequence(main_seq_thread, seq_id, pos); 718 719 seq_animates_vis = shape->sequences[seq_id].visMatters.testAll(); 720 } 721 722 last_anim_tag = unique_anim_tag_counter++; 723 724 return last_anim_tag; 725} 726 727void afxModel::resetAnimation(U32 tag) 728{ 729 // check if this is a blended clip 730 if ((tag & 0x80000000) != 0) 731 { 732 for (S32 i = 0; i < blend_clips.size(); i++) 733 { 734 if (blend_clips[i].tag == tag) 735 { 736 if (blend_clips[i].thread) 737 { 738 //Con::printf("DESTROY THREAD %d of %d tag=%d" , i, blend_clips.size(), tag & 0x7fffffff); 739 shape_inst->destroyThread(blend_clips[i].thread); 740 } 741 blend_clips.erase_fast(i); 742 break; 743 } 744 } 745 return; 746 } 747 748 if (tag != 0 && tag == last_anim_tag) 749 { 750 // restore original non-animated state 751 if (main_seq_id == -1) 752 { 753 shape_inst->destroyThread(main_seq_thread); 754 main_seq_thread = 0; 755 } 756 // restore original sequence 757 else 758 { 759 shape_inst->setTimeScale(main_seq_thread, seq_rate_factor*mDataBlock->seq_rate); 760 shape_inst->transitionToSequence(main_seq_thread, main_seq_id , 0.0f, 0.25f, true); 761 } 762 last_anim_tag = 0; 763 } 764} 765 766F32 afxModel::getAnimClipDuration(const char* clip) 767{ 768 if (!shape_inst) 769 return 0.0f; 770 771 TSShape* shape = shape_inst->getShape(); 772 S32 seq_id = shape->findSequence(clip); 773 return (seq_id != -1) ? shape->sequences[seq_id].duration : 0.0f; 774} 775 776//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 777