1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906 |
- //-----------------------------------------------------------------------------
- // 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()
- {
- docsURL;
- 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("Animation");
- addField("playAmbient", TypeBool, Offset(mPlayAmbient, TSStatic),
- "Enables automatic playing of the animation sequence named \"ambient\" (if it exists) when the TSStatic is loaded.");
- addFieldV("AnimOffset", TypeF32, Offset(mAnimOffset, TSStatic), &percentValidator,
- "Percent Animation Offset.");
- addFieldV("AnimSpeed", TypeF32, Offset(mAnimSpeed, TSStatic), &speedValidator,
- "Percent Animation Speed.");
- endGroup("Animation");
- addGroup("Rendering");
- 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;
- }
|