123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "platform/platform.h"
- #include "T3D/tsStatic.h"
- #include "core/resourceManager.h"
- #include "core/stream/bitStream.h"
- #include "scene/sceneRenderState.h"
- #include "scene/sceneManager.h"
- #include "scene/sceneObjectLightingPlugin.h"
- #include "lighting/lightManager.h"
- #include "math/mathIO.h"
- #include "ts/tsShapeInstance.h"
- #include "ts/tsMaterialList.h"
- #include "console/consoleTypes.h"
- #include "T3D/shapeBase.h"
- #include "sim/netConnection.h"
- #include "gfx/gfxDevice.h"
- #include "gfx/gfxTransformSaver.h"
- #include "ts/tsRenderState.h"
- #include "collision/boxConvex.h"
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/physics/physicsBody.h"
- #include "T3D/physics/physicsCollision.h"
- #include "materials/materialDefinition.h"
- #include "materials/materialManager.h"
- #include "materials/matInstance.h"
- #include "materials/materialFeatureData.h"
- #include "materials/materialFeatureTypes.h"
- #include "console/engineAPI.h"
- #include "T3D/accumulationVolume.h"
- #include "math/mTransform.h"
- #include "gui/editor/inspector/group.h"
- #include "console/typeValidators.h"
- using namespace Torque;
- extern bool gEditingMission;
- #ifdef TORQUE_AFX_ENABLED
- #include "afx/ce/afxZodiacMgr.h"
- #endif
- IMPLEMENT_CO_NETOBJECT_V1(TSStatic);
- ConsoleDocClass(TSStatic,
- "@brief A static object derived from a 3D model file and placed within the game world.\n\n"
- "TSStatic is the most basic 3D shape in Torque. Unlike StaticShape it doesn't make use of "
- "a datablock. It derrives directly from SceneObject. This makes TSStatic extremely light "
- "weight, which is why the Tools use this class when you want to drop in a DTS or DAE object.\n\n"
- "While a TSStatic doesn't provide any motion -- it stays were you initally put it -- it does allow for "
- "a single ambient animation sequence to play when the object is first added to the scene.\n\n"
- "@tsexample\n"
- "new TSStatic(Team1Base) {\n"
- " shapeName = \"art/shapes/desertStructures/station01.dts\";\n"
- " playAmbient = \"1\";\n"
- " receiveSunLight = \"1\";\n"
- " receiveLMLighting = \"1\";\n"
- " useCustomAmbientLighting = \"0\";\n"
- " customAmbientLighting = \"0 0 0 1\";\n"
- " collisionType = \"Visible Mesh\";\n"
- " decalType = \"Collision Mesh\";\n"
- " allowPlayerStep = \"1\";\n"
- " renderNormals = \"0\";\n"
- " forceDetail = \"-1\";\n"
- " position = \"315.18 -180.418 244.313\";\n"
- " rotation = \"0 0 1 195.952\";\n"
- " scale = \"1 1 1\";\n"
- " isRenderEnabled = \"true\";\n"
- " canSaveDynamicFields = \"1\";\n"
- "};\n"
- "@endtsexample\n"
- "@ingroup gameObjects\n"
- );
- bool TSStatic::smUseStaticObjectFade = false;
- F32 TSStatic::smStaticObjectFadeStart = 50;
- F32 TSStatic::smStaticObjectFadeEnd = 75;
- F32 TSStatic::smStaticObjectUnfadeableSize = 75;
- TSStatic::TSStatic()
- :
- cubeDescId(0),
- reflectorDesc(NULL)
- {
- mNetFlags.set(Ghostable | ScopeAlways);
- mTypeMask |= StaticObjectType | StaticShapeObjectType;
- mShapeInstance = NULL;
- mPlayAmbient = true;
- mAmbientThread = NULL;
- mAllowPlayerStep = false;
- mConvexList = new Convex;
- mRenderNormalScalar = 0;
- mForceDetail = -1;
- mMeshCulling = false;
- mUseOriginSort = false;
- mUseAlphaFade = false;
- mAlphaFadeStart = 100.0f;
- mAlphaFadeEnd = 150.0f;
- mInvertAlphaFade = false;
- mAlphaFade = 1.0f;
- mPhysicsRep = NULL;
- mCollisionType = CollisionMesh;
- mDecalType = CollisionMesh;
- mIgnoreZodiacs = false;
- mHasGradients = false;
- mInvertGradientRange = false;
- mGradientRangeUser.set(0.0f, 180.0f);
- #ifdef TORQUE_AFX_ENABLED
- afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser);
- #endif
- mAnimOffset = 0.0f;
- mAnimSpeed = 1.0f;
- INIT_ASSET(Shape);
- }
- TSStatic::~TSStatic()
- {
- delete mConvexList;
- mConvexList = NULL;
- }
- ImplementEnumType(TSMeshType,
- "Type of mesh data available in a shape.\n"
- "@ingroup gameObjects")
- {
- TSStatic::None, "None", "No mesh data."
- },
- { TSStatic::Bounds, "Bounds", "Bounding box of the shape." },
- { TSStatic::CollisionMesh, "Collision Mesh", "Specifically desingated \"collision\" meshes." },
- { TSStatic::VisibleMesh, "Visible Mesh", "Rendered mesh polygons." },
- EndImplementEnumType;
- FRangeValidator percentValidator(0.0f, 1.0f);
- F32 AnimSpeedMax = 4.0f;
- FRangeValidator speedValidator(0.0f, AnimSpeedMax);
- void TSStatic::initPersistFields()
- {
- addFieldV("AnimOffset", TypeF32, Offset(mAnimOffset, TSStatic), &percentValidator,
- "Percent Animation Offset.");
- addFieldV("AnimSpeed", TypeF32, Offset(mAnimSpeed, TSStatic), &speedValidator,
- "Percent Animation Speed.");
- addGroup("Shape");
- INITPERSISTFIELD_SHAPEASSET(Shape, TSStatic, "Model to use for this TSStatic");
- addProtectedField("shapeName", TypeShapeFilename, Offset(mShapeName, TSStatic),
- &TSStatic::_setShapeData, &defaultProtectedGetFn,
- "%Path and filename of the model file (.DTS, .DAE) to use for this TSStatic. Legacy field. Any loose files assigned here will attempt to be auto-imported in as an asset.", AbstractClassRep::FIELD_HideInInspectors);
- endGroup("Shape");
- addGroup("Materials");
- addProtectedField("skin", TypeRealString, Offset(mAppliedSkinName, TSStatic), &_setFieldSkin, &_getFieldSkin,
- "@brief The skin applied to the shape.\n\n"
- "'Skinning' the shape effectively renames the material targets, allowing "
- "different materials to be used on different instances of the same model.\n\n"
- "Any material targets that start with the old skin name have that part "
- "of the name replaced with the new skin name. The initial old skin name is "
- "\"base\". For example, if a new skin of \"blue\" was applied to a model "
- "that had material targets <i>base_body</i> and <i>face</i>, the new targets "
- "would be <i>blue_body</i> and <i>face</i>. Note that <i>face</i> was not "
- "renamed since it did not start with the old skin name of \"base\".\n\n"
- "To support models that do not use the default \"base\" naming convention, "
- "you can also specify the part of the name to replace in the skin field "
- "itself. For example, if a model had a material target called <i>shapemat</i>, "
- "we could apply a new skin \"shape=blue\", and the material target would be "
- "renamed to <i>bluemat</i> (note \"shape\" has been replaced with \"blue\").\n\n"
- "Multiple skin updates can also be applied at the same time by separating "
- "them with a semicolon. For example: \"base=blue;face=happy_face\".\n\n"
- "Material targets are only renamed if an existing Material maps to that "
- "name, or if there is a diffuse texture in the model folder with the same "
- "name as the new target.\n\n");
- endGroup("Materials");
- addGroup("Rendering");
- addField("playAmbient", TypeBool, Offset(mPlayAmbient, TSStatic),
- "Enables automatic playing of the animation sequence named \"ambient\" (if it exists) when the TSStatic is loaded.");
- addField("meshCulling", TypeBool, Offset(mMeshCulling, TSStatic),
- "Enables detailed culling of meshes within the TSStatic. Should only be used "
- "with large complex shapes like buildings which contain many submeshes.");
- addField("originSort", TypeBool, Offset(mUseOriginSort, TSStatic),
- "Enables translucent sorting of the TSStatic by its origin instead of the bounds.");
- endGroup("Rendering");
- addGroup("Reflection");
- addField("cubeReflectorDesc", TypeRealString, Offset(cubeDescName, TSStatic),
- "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
- endGroup("Reflection");
- addGroup("Collision");
- addField("collisionType", TypeTSMeshType, Offset(mCollisionType, TSStatic),
- "The type of mesh data to use for collision queries.");
- addField("decalType", TypeTSMeshType, Offset(mDecalType, TSStatic),
- "The type of mesh data used to clip decal polygons against.");
- addField("allowPlayerStep", TypeBool, Offset(mAllowPlayerStep, TSStatic),
- "@brief Allow a Player to walk up sloping polygons in the TSStatic (based on the collisionType).\n\n"
- "When set to false, the slightest bump will stop the player from walking on top of the object.\n");
- endGroup("Collision");
- addGroup("AlphaFade");
- addField("alphaFadeEnable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade");
- addField("alphaFadeStart", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade");
- addField("alphaFadeEnd", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade");
- addField("alphaFadeInverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance");
- endGroup("AlphaFade");
- addGroup("Debug");
- addField("renderNormals", TypeF32, Offset(mRenderNormalScalar, TSStatic),
- "Debug rendering mode shows the normals for each point in the TSStatic's mesh.");
- addField("forceDetail", TypeS32, Offset(mForceDetail, TSStatic),
- "Forces rendering to a particular detail level.");
- endGroup("Debug");
- addGroup("AFX");
- addField("ignoreZodiacs", TypeBool, Offset(mIgnoreZodiacs, TSStatic));
- addField("useGradientRange", TypeBool, Offset(mHasGradients, TSStatic));
- addField("gradientRange", TypePoint2F, Offset(mGradientRangeUser, TSStatic));
- addField("invertGradientRange", TypeBool, Offset(mInvertGradientRange, TSStatic));
- endGroup("AFX");
- Parent::initPersistFields();
- }
- void TSStatic::consoleInit()
- {
- Parent::consoleInit();
- // Vars for debug rendering while the RoadEditor is open, only used if smEditorOpen is true.
- Con::addVariable("$pref::useStaticObjectFade", TypeBool, &TSStatic::smUseStaticObjectFade, "Indicates if all statics should utilize the distance-based object fadeout logic.\n");
- Con::addVariable("$pref::staticObjectFadeStart", TypeF32, &TSStatic::smStaticObjectFadeStart, "Distance at which static object fading begins if $pref::useStaticObjectFade is on.\n");
- Con::addVariable("$pref::staticObjectFadeEnd", TypeF32, &TSStatic::smStaticObjectFadeEnd, "Distance at which static object fading should have fully faded if $pref::useStaticObjectFade is on.\n");
- Con::addVariable("$pref::staticObjectUnfadeableSize", TypeF32, &TSStatic::smStaticObjectUnfadeableSize, "Size of object where if the bounds is at or bigger than this, it will be ignored in the $pref::useStaticObjectFade logic. Useful for very large, distance-important objects.\n");
- }
- bool TSStatic::_setFieldSkin(void* object, const char* index, const char* data)
- {
- TSStatic* ts = static_cast<TSStatic*>(object);
- if (ts)
- ts->setSkinName(data);
- return false;
- }
- const char* TSStatic::_getFieldSkin(void* object, const char* data)
- {
- TSStatic* ts = static_cast<TSStatic*>(object);
- return ts ? ts->mSkinNameHandle.getString() : "";
- }
- void TSStatic::inspectPostApply()
- {
- // Apply any transformations set in the editor
- Parent::inspectPostApply();
- if (isServerObject())
- {
- setMaskBits(-1);
- prepCollision();
- }
- _updateShouldTick();
- }
- bool TSStatic::onAdd()
- {
- PROFILE_SCOPE(TSStatic_onAdd);
- if (isServerObject())
- {
- // Handle the old "usePolysoup" field
- SimFieldDictionary* fieldDict = getFieldDictionary();
- if (fieldDict)
- {
- StringTableEntry slotName = StringTable->insert("usePolysoup");
- SimFieldDictionary::Entry* entry = fieldDict->findDynamicField(slotName);
- if (entry)
- {
- // Was "usePolysoup" set?
- bool usePolysoup = dAtob(entry->value);
- // "usePolysoup" maps to the new VisibleMesh type
- if (usePolysoup)
- mCollisionType = VisibleMesh;
- // Remove the field in favor on the new "collisionType" field
- fieldDict->setFieldValue(slotName, "");
- }
- }
- }
- if (!Parent::onAdd())
- return false;
- // Setup the shape.
- if (!_createShape())
- {
- Con::errorf("TSStatic::onAdd() - Shape creation failed!");
- return false;
- }
- setRenderTransform(mObjToWorld);
- // Register for the resource change signal.
- //ResourceManager::get().getChangedSignal().notify(this, &TSStatic::_onResourceChanged);
- addToScene();
- if (isClientObject())
- {
- mCubeReflector.unregisterReflector();
- if (reflectorDesc)
- mCubeReflector.registerReflector(this, reflectorDesc);
- }
- _updateShouldTick();
- // Accumulation and environment mapping
- if (isClientObject() && mShapeInstance)
- {
- AccumulationVolume::addObject(this);
- }
- return true;
- }
- bool TSStatic::_createShape()
- {
- // Cleanup before we create.
- mCollisionDetails.clear();
- mDecalDetails.clear();
- mDecalDetailsPtr = 0;
- mLOSDetails.clear();
- SAFE_DELETE(mPhysicsRep);
- SAFE_DELETE(mShapeInstance);
- mAmbientThread = NULL;
- mShape = NULL;
- if(!mShapeAsset.isNull())
- {
- //Special-case handling, usually because we set noShape
- mShape = mShapeAsset->getShapeResource();
- }
- if (!mShape)
- {
- Con::errorf("TSStatic::_createShape() - Shape Asset %s had no valid shape!", mShapeAsset.getAssetId());
- return false;
- }
- if (isClientObject() &&
- !mShape->preloadMaterialList(mShape.getPath()) &&
- NetConnection::filesWereDownloaded())
- return false;
- mObjBox = mShape->mBounds;
- resetWorldBox();
- mShapeInstance = new TSShapeInstance(mShape, isClientObject());
- mShapeInstance->resetMaterialList();
- mShapeInstance->cloneMaterialList();
- if (isGhost())
- {
- // Reapply the current skin
- mAppliedSkinName = "";
- reSkin();
- updateMaterials();
- }
- prepCollision();
- // Find the "ambient" animation if it exists
- S32 ambientSeq = mShape->findSequence("ambient");
- if (ambientSeq > -1 && !mAmbientThread)
- mAmbientThread = mShapeInstance->addThread();
- if ( mAmbientThread )
- mShapeInstance->setSequence(mAmbientThread, ambientSeq, mAnimOffset);
- // Resolve CubeReflectorDesc.
- if (cubeDescName.isNotEmpty())
- {
- Sim::findObject(cubeDescName, reflectorDesc);
- }
- else if (cubeDescId > 0)
- {
- Sim::findObject(cubeDescId, reflectorDesc);
- }
- //Set up the material slot vars for easy manipulation
- /*S32 materialCount = mShape->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount();
- //Temporarily disabled until fixup of materialName->assetId lookup logic is sorted for easy persistance
- if (isServerObject())
- {
- char matFieldName[128];
- for (U32 i = 0; i < materialCount; i++)
- {
- StringTableEntry materialname = StringTable->insert(mShape->materialList->getMaterialName(i).c_str());
- dSprintf(matFieldName, 128, "MaterialSlot%d", i);
- StringTableEntry matFld = StringTable->insert(matFieldName);
- setDataField(matFld, NULL, materialname);
- }
- }*/
- return true;
- }
- void TSStatic::onDynamicModified(const char* slotName, const char* newValue)
- {
- if (FindMatch::isMatch("materialslot*", slotName, false))
- {
- if (!getShape())
- return;
- S32 slot = -1;
- String outStr(String::GetTrailingNumber(slotName, slot));
- if (slot == -1)
- return;
- //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name
- MaterialAsset* matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newValue);
- if (!matAsset)
- return;
- bool found = false;
- for (U32 i = 0; i < mChangingMaterials.size(); i++)
- {
- if (mChangingMaterials[i].slot == slot)
- {
- mChangingMaterials[i].matAsset = matAsset;
- mChangingMaterials[i].assetId = newValue;
- found = true;
- }
- }
- if (!found)
- {
- matMap newMatMap;
- newMatMap.slot = slot;
- newMatMap.matAsset = matAsset;
- newMatMap.assetId = newValue;
- mChangingMaterials.push_back(newMatMap);
- }
- setMaskBits(MaterialMask);
- }
- Parent::onDynamicModified(slotName, newValue);
- }
- void TSStatic::prepCollision()
- {
- // Let the client know that the collision was updated
- setMaskBits(UpdateCollisionMask);
- // Allow the ShapeInstance to prep its collision if it hasn't already
- if (mShapeInstance)
- mShapeInstance->prepCollision();
- // Cleanup any old collision data
- mCollisionDetails.clear();
- mDecalDetails.clear();
- mDecalDetailsPtr = 0;
- mLOSDetails.clear();
- mConvexList->nukeList();
- if (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh)
- {
- mShape->findColDetails(mCollisionType == VisibleMesh, &mCollisionDetails, &mLOSDetails);
- if (mDecalType == mCollisionType)
- {
- mDecalDetailsPtr = &mCollisionDetails;
- }
- else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh)
- {
- mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0);
- mDecalDetailsPtr = &mDecalDetails;
- }
- }
- else if (mDecalType == CollisionMesh || mDecalType == VisibleMesh)
- {
- mShape->findColDetails(mDecalType == VisibleMesh, &mDecalDetails, 0);
- mDecalDetailsPtr = &mDecalDetails;
- }
- _updatePhysics();
- }
- void TSStatic::_updatePhysics()
- {
- SAFE_DELETE(mPhysicsRep);
- if (!PHYSICSMGR || mCollisionType == None)
- return;
- PhysicsCollision* colShape = NULL;
- if (mCollisionType == Bounds)
- {
- MatrixF offset(true);
- offset.setPosition(mShape->center);
- colShape = PHYSICSMGR->createCollision();
- colShape->addBox(getObjBox().getExtents() * 0.5f * mObjScale, offset);
- }
- else
- colShape = mShape->buildColShape(mCollisionType == VisibleMesh, getScale());
- if (colShape)
- {
- PhysicsWorld* world = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
- mPhysicsRep = PHYSICSMGR->createBody();
- mPhysicsRep->init(colShape, 0, 0, this, world);
- mPhysicsRep->setTransform(getTransform());
- }
- }
- void TSStatic::onRemove()
- {
- SAFE_DELETE(mPhysicsRep);
- // Accumulation
- if (isClientObject() && mShapeInstance)
- {
- if (mShapeInstance->hasAccumulation())
- AccumulationVolume::removeObject(this);
- }
- mConvexList->nukeList();
- removeFromScene();
- // Remove the resource change signal.
- //ResourceManager::get().getChangedSignal().remove(this, &TSStatic::_onResourceChanged);
- delete mShapeInstance;
- mShapeInstance = NULL;
- mAmbientThread = NULL;
- if (isClientObject())
- mCubeReflector.unregisterReflector();
- Parent::onRemove();
- }
- void TSStatic::_onResourceChanged(const Torque::Path& path)
- {
- if (path != Path(mShapeName))
- return;
- _createShape();
- _updateShouldTick();
- }
- void TSStatic::onShapeChanged()
- {
- _createShape();
- _updateShouldTick();
- }
- void TSStatic::setSkinName(const char* name)
- {
- if (!isGhost())
- {
- if (name[0] != '\0')
- {
- // Use tags for better network performance
- // Should be a tag, but we'll convert to one if it isn't.
- if (name[0] == StringTagPrefixByte)
- mSkinNameHandle = NetStringHandle(U32(dAtoi(name + 1)));
- else
- mSkinNameHandle = NetStringHandle(name);
- }
- else
- mSkinNameHandle = NetStringHandle();
- setMaskBits(SkinMask);
- }
- }
- void TSStatic::reSkin()
- {
- if (isGhost() && mShapeInstance)
- {
- if (mSkinNameHandle.isValidString())
- {
- mShapeInstance->resetMaterialList();
- Vector<String> skins;
- String(mSkinNameHandle.getString()).split(";", skins);
- for (S32 i = 0; i < skins.size(); i++)
- {
- String oldSkin(mAppliedSkinName.c_str());
- String newSkin(skins[i]);
- // Check if the skin handle contains an explicit "old" base string. This
- // allows all models to support skinning, even if they don't follow the
- // "base_xxx" material naming convention.
- S32 split = newSkin.find('='); // "old=new" format skin?
- if (split != String::NPos)
- {
- oldSkin = newSkin.substr(0, split);
- newSkin = newSkin.erase(0, split + 1);
- }
- else
- {
- oldSkin = "";
- }
- mShapeInstance->reSkin(newSkin, oldSkin);
- mAppliedSkinName = newSkin;
- }
- }
- else
- {
- mShapeInstance->reSkin("", mAppliedSkinName);
- mAppliedSkinName = "";
- }
- }
- }
- void TSStatic::processTick(const Move* move)
- {
- if ( isServerObject() && mPlayAmbient && mAmbientThread )
- {
- mShapeInstance->setTimeScale(mAmbientThread, mAnimSpeed);
- mShapeInstance->advanceTime( TickSec, mAmbientThread );
- }
- if (isMounted())
- {
- MatrixF mat(true);
- mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat);
- setTransform(mat);
- }
- }
- void TSStatic::interpolateTick(F32 delta)
- {
- }
- void TSStatic::advanceTime(F32 dt)
- {
- if ( mPlayAmbient && mAmbientThread )
- {
- mShapeInstance->setTimeScale(mAmbientThread, mAnimSpeed);
- mShapeInstance->advanceTime( dt, mAmbientThread );
- }
- if (isMounted())
- {
- MatrixF mat(true);
- mMount.object->getRenderMountTransform(dt, mMount.node, mMount.xfm, &mat);
- setRenderTransform(mat);
- }
- }
- void TSStatic::_updateShouldTick()
- {
- bool shouldTick = (mPlayAmbient && mAmbientThread) || isMounted();
- if (isTicking() != shouldTick)
- setProcessTick(shouldTick);
- }
- void TSStatic::prepRenderImage(SceneRenderState* state)
- {
- if (!mShapeInstance)
- return;
- Point3F cameraOffset;
- getRenderTransform().getColumn(3, &cameraOffset);
- cameraOffset -= state->getDiffuseCameraPosition();
- F32 dist = cameraOffset.len();
- if (dist < 0.01f)
- dist = 0.01f;
- if (mUseAlphaFade)
- {
- mAlphaFade = 1.0f;
- if ((mAlphaFadeStart < mAlphaFadeEnd) && mAlphaFadeStart > 0.1f)
- {
- if (mInvertAlphaFade)
- {
- if (dist <= mAlphaFadeStart)
- {
- return;
- }
- if (dist < mAlphaFadeEnd)
- {
- mAlphaFade = ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
- }
- }
- else
- {
- if (dist >= mAlphaFadeEnd)
- {
- return;
- }
- if (dist > mAlphaFadeStart)
- {
- mAlphaFade -= ((dist - mAlphaFadeStart) / (mAlphaFadeEnd - mAlphaFadeStart));
- }
- }
- }
- }
- else if (smUseStaticObjectFade)
- {
- F32 boundsLen = getWorldSphere().radius;
- if (boundsLen < smStaticObjectUnfadeableSize)
- {
- F32 distAdjust = (boundsLen) / (smStaticObjectUnfadeableSize);
- distAdjust = 1 - distAdjust;
- dist *= distAdjust;
- mAlphaFade = 1.0f;
- if ((smStaticObjectFadeStart < smStaticObjectFadeEnd) && smStaticObjectFadeStart > 0.1f)
- {
- if (dist >= smStaticObjectFadeEnd)
- {
- return;
- }
- if (dist > smStaticObjectFadeStart)
- {
- mAlphaFade -= ((dist - smStaticObjectFadeStart) / (smStaticObjectFadeEnd - smStaticObjectFadeStart));
- }
- }
- }
- }
- F32 invScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
- // If we're currently rendering our own reflection we
- // don't want to render ourselves into it.
- if (mCubeReflector.isRendering())
- return;
- if (mForceDetail == -1)
- mShapeInstance->setDetailFromDistance(state, dist * invScale);
- else
- mShapeInstance->setCurrentDetail(mForceDetail);
- if (mShapeInstance->getCurrentDetail() < 0)
- return;
- GFXTransformSaver saver;
- // Set up our TS render state.
- TSRenderState rdata;
- rdata.setSceneState(state);
- rdata.setFadeOverride(1.0f);
- rdata.setOriginSort(mUseOriginSort);
- if (mCubeReflector.isEnabled())
- rdata.setCubemap(mCubeReflector.getCubemap());
- // Acculumation
- rdata.setAccuTex(mAccuTex);
- // If we have submesh culling enabled then prepare
- // the object space frustum to pass to the shape.
- Frustum culler;
- if (mMeshCulling)
- {
- culler = state->getCullingFrustum();
- MatrixF xfm(true);
- xfm.scale(Point3F::One / getScale());
- xfm.mul(getRenderWorldTransform());
- xfm.mul(culler.getTransform());
- culler.setTransform(xfm);
- rdata.setCuller(&culler);
- }
- // We might have some forward lit materials
- // so pass down a query to gather lights.
- LightQuery query;
- query.init(getWorldSphere());
- rdata.setLightQuery(&query);
- MatrixF mat = getRenderTransform();
- mat.scale(mObjScale);
- GFX->setWorldMatrix(mat);
- if (state->isDiffusePass() && mCubeReflector.isEnabled() && mCubeReflector.getOcclusionQuery())
- {
- RenderPassManager* pass = state->getRenderPass();
- OccluderRenderInst* ri = pass->allocInst<OccluderRenderInst>();
- ri->type = RenderPassManager::RIT_Occluder;
- ri->query = mCubeReflector.getOcclusionQuery();
- mObjToWorld.mulP(mObjBox.getCenter(), &ri->position);
- ri->scale.set(mObjBox.getExtents());
- ri->orientation = pass->allocUniqueXform(mObjToWorld);
- ri->isSphere = false;
- state->getRenderPass()->addInst(ri);
- }
- if (mShapeInstance)
- {
- mShapeInstance->animate();
- if (mUseAlphaFade || smUseStaticObjectFade)
- {
- mShapeInstance->setAlphaAlways(mAlphaFade);
- S32 s = mShapeInstance->mMeshObjects.size();
- for (S32 x = 0; x < s; x++)
- {
- mShapeInstance->mMeshObjects[x].visible = mAlphaFade;
- }
- }
- }
- mShapeInstance->render(rdata);
- #ifdef TORQUE_AFX_ENABLED
- if (!mIgnoreZodiacs && mDecalDetailsPtr != 0)
- afxZodiacMgr::renderPolysoupZodiacs(state, this);
- #endif
- if (mRenderNormalScalar > 0)
- {
- ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
- ri->renderDelegate.bind(this, &TSStatic::_renderNormals);
- ri->type = RenderPassManager::RIT_Editor;
- state->getRenderPass()->addInst(ri);
- }
- }
- void TSStatic::_renderNormals(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat)
- {
- PROFILE_SCOPE(TSStatic_RenderNormals);
- GFXTransformSaver saver;
- MatrixF mat = getRenderTransform();
- mat.scale(mObjScale);
- GFX->multWorld(mat);
- S32 dl = mShapeInstance->getCurrentDetail();
- mShapeInstance->renderDebugNormals(mRenderNormalScalar, dl);
- }
- void TSStatic::onScaleChanged()
- {
- Parent::onScaleChanged();
- if (mPhysicsRep)
- {
- // If the editor is enabled delay the scale operation
- // by a few milliseconds so that we're not rebuilding
- // during an active scale drag operation.
- if (gEditingMission)
- mPhysicsRep->queueCallback(500, Delegate<void()>(this, &TSStatic::_updatePhysics));
- else
- _updatePhysics();
- }
- setMaskBits(ScaleMask);
- }
- void TSStatic::setTransform(const MatrixF& mat)
- {
- Parent::setTransform(mat);
- if (!isMounted())
- setMaskBits(TransformMask);
- if (mPhysicsRep)
- mPhysicsRep->setTransform(mat);
- // Accumulation
- if (isClientObject() && mShapeInstance)
- {
- if (mShapeInstance->hasAccumulation())
- AccumulationVolume::updateObject(this);
- }
- // Since this is a static it's render transform changes 1
- // to 1 with it's collision transform... no interpolation.
- setRenderTransform(mat);
- }
- U32 TSStatic::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
- {
- U32 retMask = Parent::packUpdate(con, mask, stream);
- if (stream->writeFlag(mask & TransformMask))
- mathWrite(*stream, getTransform());
- if (stream->writeFlag(mask & ScaleMask))
- {
- // Only write one bit if the scale is one.
- if (stream->writeFlag(mObjScale != Point3F::One))
- mathWrite(*stream, mObjScale);
- }
- if (stream->writeFlag(mask & UpdateCollisionMask))
- stream->write((U32)mCollisionType);
- if (stream->writeFlag(mask & SkinMask))
- con->packNetStringHandleU(stream, mSkinNameHandle);
- if (stream->writeFlag(mask & AdvancedStaticOptionsMask))
- {
- PACK_ASSET(con, Shape);
- stream->write((U32)mDecalType);
- stream->writeFlag(mAllowPlayerStep);
- stream->writeFlag(mMeshCulling);
- stream->writeFlag(mUseOriginSort);
- stream->write(mRenderNormalScalar);
- stream->write(mForceDetail);
- if (stream->writeFlag(mAnimOffset != 0.0f))
- stream->writeFloat(mAnimOffset, 7);
- if (stream->writeFlag(mAnimSpeed != 1.0f))
- stream->writeSignedFloat(mAnimSpeed / AnimSpeedMax, 7);
- stream->writeFlag(mPlayAmbient);
- }
- if (stream->writeFlag(mUseAlphaFade))
- {
- stream->write(mAlphaFadeStart);
- stream->write(mAlphaFadeEnd);
- stream->write(mInvertAlphaFade);
- }
- stream->writeFlag(mIgnoreZodiacs);
- if (stream->writeFlag(mHasGradients))
- {
- stream->writeFlag(mInvertGradientRange);
- stream->write(mGradientRange.x);
- stream->write(mGradientRange.y);
- }
- if (mLightPlugin)
- retMask |= mLightPlugin->packUpdate(this, AdvancedStaticOptionsMask, con, mask, stream);
- if (stream->writeFlag(reflectorDesc != NULL))
- {
- stream->writeRangedU32(reflectorDesc->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
- }
- stream->write(mOverrideColor);
- if (stream->writeFlag(mask & MaterialMask))
- {
- stream->writeInt(mChangingMaterials.size(), 16);
- for (U32 i = 0; i < mChangingMaterials.size(); i++)
- {
- stream->writeInt(mChangingMaterials[i].slot, 16);
- NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str();
- con->packNetStringHandleU(stream, matNameStr);
- }
- //mChangingMaterials.clear();
- }
- return retMask;
- }
- void TSStatic::unpackUpdate(NetConnection* con, BitStream* stream)
- {
- Parent::unpackUpdate(con, stream);
- if (stream->readFlag()) // TransformMask
- {
- MatrixF mat;
- mathRead(*stream, &mat);
- setTransform(mat);
- setRenderTransform(mat);
- }
- if (stream->readFlag()) // ScaleMask
- {
- if (stream->readFlag())
- {
- VectorF scale;
- mathRead(*stream, &scale);
- setScale(scale);
- }
- else
- setScale(Point3F::One);
- }
- if (stream->readFlag()) // UpdateCollisionMask
- {
- U32 collisionType = CollisionMesh;
- stream->read(&collisionType);
- // Handle it if we have changed CollisionType's
- if ((MeshType)collisionType != mCollisionType)
- {
- mCollisionType = (MeshType)collisionType;
- if (isProperlyAdded() && mShapeInstance)
- prepCollision();
- }
- }
- if (stream->readFlag()) // SkinMask
- {
- NetStringHandle skinDesiredNameHandle = con->unpackNetStringHandleU(stream);;
- if (mSkinNameHandle != skinDesiredNameHandle)
- {
- mSkinNameHandle = skinDesiredNameHandle;
- reSkin();
- }
- }
- if (stream->readFlag()) // AdvancedStaticOptionsMask
- {
- UNPACK_ASSET(con, Shape);
- stream->read((U32*)&mDecalType);
- mAllowPlayerStep = stream->readFlag();
- mMeshCulling = stream->readFlag();
- mUseOriginSort = stream->readFlag();
- stream->read(&mRenderNormalScalar);
- stream->read(&mForceDetail);
- if (stream->readFlag())
- mAnimOffset = stream->readFloat(7);
- if (stream->readFlag())
- mAnimSpeed = stream->readSignedFloat(7) * AnimSpeedMax;
- mPlayAmbient = stream->readFlag();
- //update our shape, figuring that it likely changed
- _createShape();
- }
- mUseAlphaFade = stream->readFlag();
- if (mUseAlphaFade)
- {
- stream->read(&mAlphaFadeStart);
- stream->read(&mAlphaFadeEnd);
- stream->read(&mInvertAlphaFade);
- }
- mIgnoreZodiacs = stream->readFlag();
- mHasGradients = stream->readFlag();
- if (mHasGradients)
- {
- mInvertGradientRange = stream->readFlag();
- stream->read(&mGradientRange.x);
- stream->read(&mGradientRange.y);
- }
- if (mLightPlugin)
- {
- mLightPlugin->unpackUpdate(this, con, stream);
- }
- if (stream->readFlag())
- {
- cubeDescId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
- }
- stream->read(&mOverrideColor);
- if (stream->readFlag())
- {
- mChangingMaterials.clear();
- U32 materialCount = stream->readInt(16);
- for (U32 i = 0; i < materialCount; i++)
- {
- matMap newMatMap;
- newMatMap.slot = stream->readInt(16);
- newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString());
- //do the lookup, now
- newMatMap.matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newMatMap.assetId);
- mChangingMaterials.push_back(newMatMap);
- }
- updateMaterials();
- }
- if (isProperlyAdded())
- _updateShouldTick();
- set_special_typing();
- }
- //----------------------------------------------------------------------------
- bool TSStatic::castRay(const Point3F& start, const Point3F& end, RayInfo* info)
- {
- if (mCollisionType == None)
- return false;
- if (!mShapeInstance)
- return false;
- if (mCollisionType == Bounds)
- {
- F32 fst;
- if (!mObjBox.collideLine(start, end, &fst, &info->normal))
- return false;
- info->t = fst;
- info->object = this;
- info->point.interpolate(start, end, fst);
- info->material = NULL;
- return true;
- }
- else
- {
- RayInfo shortest = *info;
- RayInfo localInfo;
- shortest.t = 1e8f;
- localInfo.generateTexCoord = info->generateTexCoord;
- for (U32 i = 0; i < mLOSDetails.size(); i++)
- {
- mShapeInstance->animate(mLOSDetails[i]);
- if (mShapeInstance->castRayOpcode(mLOSDetails[i], start, end, &localInfo))
- {
- localInfo.object = this;
- if (localInfo.t < shortest.t)
- shortest = localInfo;
- }
- }
- if (shortest.object == this)
- {
- // Copy out the shortest time...
- *info = shortest;
- return true;
- }
- }
- return false;
- }
- bool TSStatic::castRayRendered(const Point3F& start, const Point3F& end, RayInfo* info)
- {
- if (!mShapeInstance)
- return false;
- // Cast the ray against the currently visible detail
- RayInfo localInfo;
- if (info && info->generateTexCoord)
- localInfo.generateTexCoord = true;
- bool res = mShapeInstance->castRayOpcode(mShapeInstance->getCurrentDetail(), start, end, &localInfo);
- if (res)
- {
- *info = localInfo;
- info->object = this;
- return true;
- }
- return false;
- }
- bool TSStatic::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF&)
- {
- if (!mShapeInstance)
- return false;
- // This is safe to set even if we're not outputing
- polyList->setTransform(&mObjToWorld, mObjScale);
- polyList->setObject(this);
- if (context == PLC_Export)
- {
- // Use highest detail level
- S32 dl = 0;
- // Try to call on the client so we can export materials
- if (isServerObject() && getClientObject())
- dynamic_cast<TSStatic*>(getClientObject())->mShapeInstance->buildPolyList(polyList, dl);
- else
- mShapeInstance->buildPolyList(polyList, dl);
- }
- else if (context == PLC_Selection)
- {
- // Use the last rendered detail level
- S32 dl = mShapeInstance->getCurrentDetail();
- mShapeInstance->buildPolyListOpcode(dl, polyList, box);
- }
- else
- {
- // Figure out the mesh type we're looking for.
- MeshType meshType = (context == PLC_Decal) ? mDecalType : mCollisionType;
- if (meshType == None)
- return false;
- else if (meshType == Bounds)
- polyList->addBox(mObjBox);
- else if (meshType == VisibleMesh)
- mShapeInstance->buildPolyList(polyList, 0);
- else if (context == PLC_Decal && mDecalDetailsPtr != 0)
- {
- for (U32 i = 0; i < mDecalDetailsPtr->size(); i++)
- mShapeInstance->buildPolyListOpcode((*mDecalDetailsPtr)[i], polyList, box);
- }
- else
- {
- // Everything else is done from the collision meshes
- // which may be built from either the visual mesh or
- // special collision geometry.
- for (U32 i = 0; i < mCollisionDetails.size(); i++)
- mShapeInstance->buildPolyListOpcode(mCollisionDetails[i], polyList, box);
- }
- }
- return true;
- }
- bool TSStatic::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF&)
- {
- if (!mShapeInstance)
- return false;
- if (mCollisionType == Bounds)
- {
- ColladaUtils::ExportData::colMesh* colMesh;
- exportData->colMeshes.increment();
- colMesh = &exportData->colMeshes.last();
- colMesh->mesh.setTransform(&mObjToWorld, mObjScale);
- colMesh->mesh.setObject(this);
- colMesh->mesh.addBox(mObjBox);
- colMesh->colMeshName = String::ToString("ColBox%d-1", exportData->colMeshes.size());
- }
- else if (mCollisionType == VisibleMesh)
- {
- ColladaUtils::ExportData::colMesh* colMesh;
- exportData->colMeshes.increment();
- colMesh = &exportData->colMeshes.last();
- colMesh->mesh.setTransform(&mObjToWorld, mObjScale);
- colMesh->mesh.setObject(this);
- mShapeInstance->buildPolyList(&colMesh->mesh, 0);
- colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size());
- }
- else if (mCollisionType == CollisionMesh)
- {
- // Everything else is done from the collision meshes
- // which may be built from either the visual mesh or
- // special collision geometry.
- for (U32 i = 0; i < mCollisionDetails.size(); i++)
- {
- ColladaUtils::ExportData::colMesh* colMesh;
- exportData->colMeshes.increment();
- colMesh = &exportData->colMeshes.last();
- colMesh->mesh.setTransform(&mObjToWorld, mObjScale);
- colMesh->mesh.setObject(this);
- mShapeInstance->buildPolyListOpcode(mCollisionDetails[i], &colMesh->mesh, box);
- colMesh->colMeshName = String::ToString("ColMesh%d-1", exportData->colMeshes.size());
- }
- }
- //Next, process the LOD levels and materials.
- if (isServerObject() && getClientObject())
- {
- TSStatic* clientShape = dynamic_cast<TSStatic*>(getClientObject());
- exportData->meshData.increment();
- //Prep a meshData for this shape in particular
- ColladaUtils::ExportData::meshLODData* meshData = &exportData->meshData.last();
- //Fill out the info we'll need later to actually append our mesh data for the detail levels during the processing phase
- meshData->shapeInst = clientShape->mShapeInstance;
- meshData->originatingObject = this;
- meshData->meshTransform = mObjToWorld;
- meshData->scale = mObjScale;
- //Iterate over all our detail levels
- for (U32 i = 0; i < clientShape->mShapeInstance->getNumDetails(); i++)
- {
- TSShape::Detail detail = clientShape->mShapeInstance->getShape()->details[i];
- String detailName = String::ToLower(clientShape->mShapeInstance->getShape()->getName(detail.nameIndex));
- //Skip it if it's a collision or line of sight element
- if (detailName.startsWith("col") || detailName.startsWith("los"))
- continue;
- meshData->meshDetailLevels.increment();
- ColladaUtils::ExportData::detailLevel* curDetail = &meshData->meshDetailLevels.last();
- //Make sure we denote the size this detail level has
- curDetail->size = getNextPow2(detail.size);
- }
- }
- return true;
- }
- void TSStatic::buildConvex(const Box3F& box, Convex* convex)
- {
- if (mCollisionType == None)
- return;
- if (mShapeInstance == NULL)
- return;
- // These should really come out of a pool
- mConvexList->collectGarbage();
- if (mCollisionType == Bounds)
- {
- // Just return a box convex for the entire shape...
- Convex* cc = 0;
- CollisionWorkingList& wl = convex->getWorkingList();
- for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
- {
- if (itr->mConvex->getType() == BoxConvexType &&
- itr->mConvex->getObject() == this)
- {
- cc = itr->mConvex;
- break;
- }
- }
- if (cc)
- return;
- // Create a new convex.
- BoxConvex* cp = new BoxConvex;
- mConvexList->registerObject(cp);
- convex->addToWorkingList(cp);
- cp->init(this);
- mObjBox.getCenter(&cp->mCenter);
- cp->mSize.x = mObjBox.len_x() / 2.0f;
- cp->mSize.y = mObjBox.len_y() / 2.0f;
- cp->mSize.z = mObjBox.len_z() / 2.0f;
- }
- else // CollisionMesh || VisibleMesh
- {
- TSStaticPolysoupConvex::smCurObject = this;
- for (U32 i = 0; i < mCollisionDetails.size(); i++)
- mShapeInstance->buildConvexOpcode(mObjToWorld, mObjScale, mCollisionDetails[i], box, convex, mConvexList);
- TSStaticPolysoupConvex::smCurObject = NULL;
- }
- }
- SceneObject* TSStaticPolysoupConvex::smCurObject = NULL;
- TSStaticPolysoupConvex::TSStaticPolysoupConvex()
- : box(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f),
- normal(0.0f, 0.0f, 0.0f, 0.0f),
- idx(0),
- mesh(NULL)
- {
- mType = TSPolysoupConvexType;
- for (U32 i = 0; i < 4; ++i)
- {
- verts[i].set(0.0f, 0.0f, 0.0f);
- }
- }
- Point3F TSStaticPolysoupConvex::support(const VectorF& vec) const
- {
- F32 bestDot = mDot(verts[0], vec);
- const Point3F* bestP = &verts[0];
- for (S32 i = 1; i < 4; i++)
- {
- F32 newD = mDot(verts[i], vec);
- if (newD > bestDot)
- {
- bestDot = newD;
- bestP = &verts[i];
- }
- }
- return *bestP;
- }
- Box3F TSStaticPolysoupConvex::getBoundingBox() const
- {
- Box3F wbox = box;
- wbox.minExtents.convolve(mObject->getScale());
- wbox.maxExtents.convolve(mObject->getScale());
- mObject->getTransform().mul(wbox);
- return wbox;
- }
- Box3F TSStaticPolysoupConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const
- {
- AssertISV(false, "TSStaticPolysoupConvex::getBoundingBox(m,p) - Not implemented. -- XEA");
- return box;
- }
- void TSStaticPolysoupConvex::getPolyList(AbstractPolyList* list)
- {
- // Transform the list into object space and set the pointer to the object
- MatrixF i(mObject->getTransform());
- Point3F iS(mObject->getScale());
- list->setTransform(&i, iS);
- list->setObject(mObject);
- // Add only the original collision triangle
- S32 base = list->addPoint(verts[0]);
- list->addPoint(verts[2]);
- list->addPoint(verts[1]);
- list->begin(0, (U32)idx ^ (uintptr_t)mesh);
- list->vertex(base + 2);
- list->vertex(base + 1);
- list->vertex(base + 0);
- list->plane(base + 0, base + 1, base + 2);
- list->end();
- }
- void TSStaticPolysoupConvex::getFeatures(const MatrixF& mat, const VectorF& n, ConvexFeature* cf)
- {
- cf->material = 0;
- cf->mObject = mObject;
- // For a tetrahedron this is pretty easy... first
- // convert everything into world space.
- Point3F tverts[4];
- mat.mulP(verts[0], &tverts[0]);
- mat.mulP(verts[1], &tverts[1]);
- mat.mulP(verts[2], &tverts[2]);
- mat.mulP(verts[3], &tverts[3]);
- // points...
- S32 firstVert = cf->mVertexList.size();
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[0];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[1];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[2];
- cf->mVertexList.increment(); cf->mVertexList.last() = tverts[3];
- // edges...
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 0;
- cf->mEdgeList.last().vertex[1] = firstVert + 1;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 1;
- cf->mEdgeList.last().vertex[1] = firstVert + 2;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 2;
- cf->mEdgeList.last().vertex[1] = firstVert + 0;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 3;
- cf->mEdgeList.last().vertex[1] = firstVert + 0;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 3;
- cf->mEdgeList.last().vertex[1] = firstVert + 1;
- cf->mEdgeList.increment();
- cf->mEdgeList.last().vertex[0] = firstVert + 3;
- cf->mEdgeList.last().vertex[1] = firstVert + 2;
- // triangles...
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[0]);
- cf->mFaceList.last().vertex[0] = firstVert + 2;
- cf->mFaceList.last().vertex[1] = firstVert + 1;
- cf->mFaceList.last().vertex[2] = firstVert + 0;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[1], tverts[0], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert + 1;
- cf->mFaceList.last().vertex[1] = firstVert + 0;
- cf->mFaceList.last().vertex[2] = firstVert + 3;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[2], tverts[1], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert + 2;
- cf->mFaceList.last().vertex[1] = firstVert + 1;
- cf->mFaceList.last().vertex[2] = firstVert + 3;
- cf->mFaceList.increment();
- cf->mFaceList.last().normal = PlaneF(tverts[0], tverts[2], tverts[3]);
- cf->mFaceList.last().vertex[0] = firstVert + 0;
- cf->mFaceList.last().vertex[1] = firstVert + 2;
- cf->mFaceList.last().vertex[2] = firstVert + 3;
- // All done!
- }
- void TSStatic::onMount(SceneObject* obj, S32 node)
- {
- Parent::onMount(obj, node);
- _updateShouldTick();
- }
- void TSStatic::onUnmount(SceneObject* obj, S32 node)
- {
- Parent::onUnmount(obj, node);
- setMaskBits(TransformMask);
- _updateShouldTick();
- }
- U32 TSStatic::getNumDetails()
- {
- if (isServerObject() && getClientObject())
- {
- TSStatic* clientShape = dynamic_cast<TSStatic*>(getClientObject());
- return clientShape->mShapeInstance->getNumDetails();
- }
- return 0;
- };
- void TSStatic::updateMaterials()
- {
- if (mChangingMaterials.empty() || !mShapeInstance)
- return;
- TSMaterialList* pMatList = mShapeInstance->getMaterialList();
- String path;
- if (mShapeAsset->isAssetValid())
- path = mShapeAsset->getShapeFileName();
- else
- path = mShapeName;
- pMatList->setTextureLookupPath(path);
- bool found = false;
- const Vector<String>& materialNames = pMatList->getMaterialNameList();
- for (S32 i = 0; i < materialNames.size(); i++)
- {
- if (found)
- break;
- for (U32 m = 0; m < mChangingMaterials.size(); m++)
- {
- if (mChangingMaterials[m].slot == i)
- {
- //Fetch the actual material asset
- pMatList->renameMaterial(i, mChangingMaterials[m].matAsset->getMaterialDefinitionName());
- found = true;
- break;
- }
- }
- }
- // Initialize the material instances
- mShapeInstance->initMaterialList();
- }
- void TSStatic::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList)
- {
- if(!mShapeAsset.isNull() && mShapeAsset->getAssetId() != ShapeAsset::smNoShapeAssetFallback)
- usedAssetsList->push_back_unique(mShapeAsset->getAssetId());
- }
- //------------------------------------------------------------------------
- //These functions are duplicated in tsStatic and shapeBase.
- //They each function a little differently; but achieve the same purpose of gathering
- //target names/counts without polluting simObject.
- #ifdef TORQUE_TOOLS
- void TSStatic::onInspect(GuiInspector* inspector)
- {
- //if (mShapeAsset == nullptr)
- return;
- //Put the GameObject group before everything that'd be gameobject-effecting, for orginazational purposes
- GuiInspectorGroup* materialGroup = inspector->findExistentGroup(StringTable->insert("Materials"));
- if (!materialGroup)
- return;
- GuiControl* stack = dynamic_cast<GuiControl*>(materialGroup->findObjectByInternalName(StringTable->insert("Stack")));
- //Do this on both the server and client
- TSMaterialList* matList = mShapeInstance->getMaterialList();
- Vector<String> matListNames = matList->getMaterialNameList();
- S32 materialCount = matListNames.size();
- if (isServerObject())
- {
- //next, get a listing of our materials in the shape, and build our field list for them
- char matFieldName[128];
- for (U32 i = 0; i < materialCount; i++)
- {
- StringTableEntry materialname = StringTable->insert(mShapeInstance->getMaterialList()->getMaterialName(i).c_str());
- AssetPtr<MaterialAsset> matAsset;
- if(MaterialAsset::getAssetByMaterialName(materialname, &matAsset) == MaterialAsset::Ok)
- {
- dSprintf(matFieldName, 128, "MaterialSlot%d", i);
- GuiInspectorField* fieldGui = materialGroup->constructField(TypeMaterialAssetPtr);
- fieldGui->init(inspector, materialGroup);
- fieldGui->setSpecialEditField(true);
- fieldGui->setTargetObject(this);
- StringTableEntry fldnm = StringTable->insert(matFieldName);
- fieldGui->setSpecialEditVariableName(fldnm);
- fieldGui->setInspectorField(NULL, fldnm);
- fieldGui->setDocs("");
- if (fieldGui->registerObject())
- {
- StringTableEntry fieldValue = matAsset->getAssetId();
- GuiInspectorTypeMaterialAssetPtr* matFieldPtr = dynamic_cast<GuiInspectorTypeMaterialAssetPtr*>(fieldGui);
- matFieldPtr->setPreviewImage(fieldValue);
- //Check if we'd already actually changed it, and display the modified value
- for (U32 c = 0; c < mChangingMaterials.size(); c++)
- {
- if (mChangingMaterials[c].slot == i)
- {
- fieldValue = StringTable->insert(mChangingMaterials[i].assetId.c_str());
- break;
- }
- }
- fieldGui->setValue(fieldValue);
- stack->addObject(fieldGui);
- }
- else
- {
- SAFE_DELETE(fieldGui);
- }
- }
- }
- }
- }
- #endif
- DefineEngineMethod(TSStatic, getTargetName, const char*, (S32 index), (0),
- "Get the name of the indexed shape material.\n"
- "@param index index of the material to get (valid range is 0 - getTargetCount()-1).\n"
- "@return the name of the indexed material.\n"
- "@see getTargetCount()\n")
- {
- TSStatic* obj = dynamic_cast<TSStatic*> (object);
- if (obj)
- {
- // Try to use the client object (so we get the reskinned targets in the Material Editor)
- if ((TSStatic*)obj->getClientObject())
- obj = (TSStatic*)obj->getClientObject();
- return obj->getShapeInstance()->getTargetName(index);
- }
- return "";
- }
- DefineEngineMethod(TSStatic, getTargetCount, S32, (), ,
- "Get the number of materials in the shape.\n"
- "@return the number of materials in the shape.\n"
- "@see getTargetName()\n")
- {
- TSStatic* obj = dynamic_cast<TSStatic*> (object);
- if (obj)
- {
- // Try to use the client object (so we get the reskinned targets in the Material Editor)
- if ((TSStatic*)obj->getClientObject())
- obj = (TSStatic*)obj->getClientObject();
- return obj->getShapeInstance()->getTargetCount();
- }
- return -1;
- }
- // This method is able to change materials per map to with others. The material that is being replaced is being mapped to
- // unmapped_mat as a part of this transition
- DefineEngineMethod(TSStatic, changeMaterial, void, (const char* mapTo, Material* oldMat, Material* newMat), ("", nullAsType<Material*>(), nullAsType<Material*>()),
- "@brief Change one of the materials on the shape.\n\n"
- "This method changes materials per mapTo with others. The material that "
- "is being replaced is mapped to unmapped_mat as a part of this transition.\n"
- "@note Warning, right now this only sort of works. It doesn't do a live "
- "update like it should.\n"
- "@param mapTo the name of the material target to remap (from getTargetName)\n"
- "@param oldMat the old Material that was mapped \n"
- "@param newMat the new Material to map\n\n"
- "@tsexample\n"
- "// remap the first material in the shape\n"
- "%mapTo = %obj.getTargetName( 0 );\n"
- "%obj.changeMaterial( %mapTo, 0, MyMaterial );\n"
- "@endtsexample\n")
- {
- // if no valid new material, theres no reason for doing this
- if (!newMat)
- {
- Con::errorf("TSShape::changeMaterial failed: New material does not exist!");
- return;
- }
- TSMaterialList* shapeMaterialList = object->getShapeResource()->materialList;
- // Check the mapTo name exists for this shape
- S32 matIndex = shapeMaterialList->getMaterialNameList().find_next(String(mapTo));
- if (matIndex < 0)
- {
- Con::errorf("TSShape::changeMaterial failed: Invalid mapTo name '%s'", mapTo);
- return;
- }
- // Lets remap the old material off, so as to let room for our current material room to claim its spot
- if (oldMat)
- oldMat->mMapTo = String("unmapped_mat");
- newMat->mMapTo = mapTo;
- // Map the material by name in the matmgr
- MATMGR->mapMaterial(mapTo, newMat->getName());
- // Replace instances with the new material being traded in. Lets make sure that we only
- // target the specific targets per inst, this is actually doing more than we thought
- delete shapeMaterialList->mMatInstList[matIndex];
- shapeMaterialList->mMatInstList[matIndex] = newMat->createMatInstance();
- // Finish up preparing the material instances for rendering
- const GFXVertexFormat* flags = getGFXVertexFormat<GFXVertexPNTTB>();
- FeatureSet features = MATMGR->getDefaultFeatures();
- shapeMaterialList->getMaterialInst(matIndex)->init(features, flags);
- }
- DefineEngineMethod(TSStatic, getModelFile, const char*, (), ,
- "@brief Get the model filename used by this shape.\n\n"
- "@return the shape filename\n\n"
- "@tsexample\n"
- "// Acquire the model filename used on this shape.\n"
- "%modelFilename = %obj.getModelFile();\n"
- "@endtsexample\n"
- )
- {
- return object->getShape();
- }
- void TSStatic::set_special_typing()
- {
- if (mCollisionType == VisibleMesh || mCollisionType == CollisionMesh)
- mTypeMask |= InteriorLikeObjectType;
- else
- mTypeMask &= ~InteriorLikeObjectType;
- }
- void TSStatic::onStaticModified(const char* slotName, const char* newValue)
- {
- #ifdef TORQUE_AFX_ENABLED
- if (slotName == afxZodiacData::GradientRangeSlot)
- {
- afxZodiacData::convertGradientRangeFromDegrees(mGradientRange, mGradientRangeUser);
- return;
- }
- #endif
- set_special_typing();
- }
- void TSStatic::setSelectionFlags(U8 flags)
- {
- Parent::setSelectionFlags(flags);
- if (!mShapeInstance || !isClientObject())
- return;
- if (!mShapeInstance->ownMaterialList())
- return;
- TSMaterialList* pMatList = mShapeInstance->getMaterialList();
- for (S32 j = 0; j < pMatList->size(); j++)
- {
- BaseMatInstance* bmi = pMatList->getMaterialInst(j);
- bmi->setSelectionHighlighting(needsSelectionHighlighting());
- }
- }
- bool TSStatic::hasNode(const char* nodeName)
- {
- S32 nodeIDx = getShapeResource()->findNode(nodeName);
- return nodeIDx >= 0;
- }
- void TSStatic::getNodeTransform(const char *nodeName, const MatrixF &xfm, MatrixF *outMat)
- {
- S32 nodeIDx = getShapeResource()->findNode(nodeName);
- MatrixF nodeTransform(xfm);
- const Point3F& scale = getScale();
- if (nodeIDx != -1)
- {
- nodeTransform = mShapeInstance->mNodeTransforms[nodeIDx];
- nodeTransform.mul(xfm);
- }
- // The position of the mount point needs to be scaled.
- Point3F position = nodeTransform.getPosition();
- position.convolve(scale);
- nodeTransform.setPosition(position);
- // Also we would like the object to be scaled to the model.
- outMat->mul(mObjToWorld, nodeTransform);
- return;
- }
- DefineEngineMethod(TSStatic, hasNode, bool, (const char* nodeName), ,
- "@brief Get if this model has this node name.\n\n")
- {
- return object->hasNode(nodeName);
- }
- DefineEngineMethod(TSStatic, getNodeTransform, TransformF, (const char *nodeName), ,
- "@brief Get the world transform of the specified node name.\n\n"
- "@param node name query\n"
- "@return the mount transform\n\n")
- {
- MatrixF xf(true);
- object->getNodeTransform(nodeName, MatrixF::Identity, &xf);
- return xf;
- }
|