meshComponent.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/consoleTypes.h"
  24. #include "T3D/components/render/meshComponent.h"
  25. #include "core/util/safeDelete.h"
  26. #include "core/resourceManager.h"
  27. #include "core/stream/fileStream.h"
  28. #include "console/consoleTypes.h"
  29. #include "console/consoleObject.h"
  30. #include "core/stream/bitStream.h"
  31. #include "sim/netConnection.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "console/engineAPI.h"
  34. #include "lighting/lightQuery.h"
  35. #include "scene/sceneManager.h"
  36. #include "gfx/bitmap/ddsFile.h"
  37. #include "gfx/gfxTextureManager.h"
  38. #include "materials/materialFeatureTypes.h"
  39. #include "renderInstance/renderImposterMgr.h"
  40. #include "util/imposterCapture.h"
  41. #include "gfx/sim/debugDraw.h"
  42. #include "gfx/gfxDrawUtil.h"
  43. #include "materials/materialManager.h"
  44. #include "materials/matInstance.h"
  45. #include "core/strings/findMatch.h"
  46. #include "T3D/components/render/meshComponent_ScriptBinding.h"
  47. //////////////////////////////////////////////////////////////////////////
  48. // Constructor/Destructor
  49. //////////////////////////////////////////////////////////////////////////
  50. MeshComponent::MeshComponent() : Component(), mShape(nullptr)
  51. {
  52. mFriendlyName = "Mesh Component";
  53. mComponentType = "Render";
  54. mDescription = getDescriptionText("Causes the object to render a non-animating 3d shape using the file provided.");
  55. mNetworked = true;
  56. mShapeName = StringTable->EmptyString();
  57. mShapeAsset = StringTable->EmptyString();
  58. mMeshAsset = StringTable->EmptyString();
  59. mMeshAssetId = StringTable->EmptyString();
  60. mInterfaceData = new MeshRenderSystemInterface();
  61. }
  62. MeshComponent::~MeshComponent()
  63. {
  64. if (mInterfaceData)
  65. SAFE_DELETE(mInterfaceData);
  66. }
  67. IMPLEMENT_CO_NETOBJECT_V1(MeshComponent);
  68. //==========================================================================================
  69. bool MeshComponent::onAdd()
  70. {
  71. if(! Parent::onAdd())
  72. return false;
  73. // Register for the resource change signal.
  74. ResourceManager::get().getChangedSignal().notify( this, &MeshComponent::_onResourceChanged );
  75. return true;
  76. }
  77. void MeshComponent::onComponentAdd()
  78. {
  79. Parent::onComponentAdd();
  80. if (isClientObject())
  81. mInterfaceData->mIsClient = true;
  82. // if (mInterfaceData != nullptr)
  83. // mInterfaceData->mIsClient = isClientObject();
  84. //get the default shape, if any
  85. updateShape();
  86. }
  87. void MeshComponent::onRemove()
  88. {
  89. Parent::onRemove();
  90. }
  91. void MeshComponent::onComponentRemove()
  92. {
  93. if(mOwner)
  94. {
  95. Point3F pos = mOwner->getPosition(); //store our center pos
  96. mOwner->setObjectBox(Box3F(Point3F(-1,-1,-1), Point3F(1,1,1)));
  97. mOwner->setPosition(pos);
  98. }
  99. Parent::onComponentRemove();
  100. }
  101. void MeshComponent::initPersistFields()
  102. {
  103. Parent::initPersistFields();
  104. //create a hook to our internal variables
  105. addGroup("Model");
  106. addProtectedField("MeshAsset", TypeShapeAssetPtr, Offset(mShapeAsset, MeshComponent), &_setMesh, &defaultProtectedGetFn, &writeShape,
  107. "The asset Id used for the mesh.", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
  108. endGroup("Model");
  109. }
  110. bool MeshComponent::_setMesh(void *object, const char *index, const char *data)
  111. {
  112. MeshComponent *rbI = static_cast<MeshComponent*>(object);
  113. // Sanity!
  114. AssertFatal(data != NULL, "Cannot use a NULL asset Id.");
  115. return rbI->setMeshAsset(data);
  116. }
  117. bool MeshComponent::_setShape( void *object, const char *index, const char *data )
  118. {
  119. MeshComponent *rbI = static_cast<MeshComponent*>(object);
  120. rbI->mShapeName = StringTable->insert(data);
  121. rbI->updateShape(); //make sure we force the update to resize the owner bounds
  122. rbI->setMaskBits(ShapeMask);
  123. return true;
  124. }
  125. bool MeshComponent::setMeshAsset(const char* assetName)
  126. {
  127. // Fetch the asset Id.
  128. if (mInterfaceData == nullptr)
  129. return false;
  130. mMeshAssetId = StringTable->insert(assetName);
  131. mMeshAsset = mMeshAssetId;
  132. if (mMeshAsset.isNull())
  133. {
  134. Con::errorf("[MeshComponent] Failed to load mesh asset.");
  135. return false;
  136. }
  137. mMeshAsset->onShapeChanged.notify(this, &MeshComponent::_shapeAssetUpdated);
  138. mShapeName = mMeshAssetId;
  139. mShapeAsset = mShapeName;
  140. updateShape(); //make sure we force the update to resize the owner bounds
  141. setMaskBits(ShapeMask);
  142. return true;
  143. }
  144. void MeshComponent::_shapeAssetUpdated(ShapeAsset* asset)
  145. {
  146. updateShape();
  147. }
  148. void MeshComponent::updateShape()
  149. {
  150. if (mInterfaceData == nullptr)
  151. return;
  152. //if ((mShapeName && mShapeName[0] != '\0') || (mShapeAsset && mShapeAsset[0] != '\0'))
  153. if ((mShapeName && mShapeName[0] != '\0') || (mMeshAssetId && mMeshAssetId[0] != '\0'))
  154. {
  155. if (mMeshAsset == NULL)
  156. return;
  157. mShape = mMeshAsset->getShape();
  158. if (!mMeshAsset->getShape())
  159. return;
  160. setupShape();
  161. //Do this on both the server and client
  162. S32 materialCount = mMeshAsset->getShape()->materialList->getMaterialNameList().size(); //mMeshAsset->getMaterialCount();
  163. if (isServerObject())
  164. {
  165. //we need to update the editor
  166. for (U32 i = 0; i < mFields.size(); i++)
  167. {
  168. //find any with the materialslot title and clear them out
  169. if (FindMatch::isMatch("MaterialSlot*", mFields[i].mFieldName, false))
  170. {
  171. setDataField(mFields[i].mFieldName, NULL, "");
  172. mFields.erase(i);
  173. continue;
  174. }
  175. }
  176. //next, get a listing of our materials in the shape, and build our field list for them
  177. char matFieldName[128];
  178. if (materialCount > 0)
  179. mComponentGroup = StringTable->insert("Materials");
  180. for (U32 i = 0; i < materialCount; i++)
  181. {
  182. StringTableEntry materialname = StringTable->insert(mMeshAsset->getShape()->materialList->getMaterialName(i).c_str());
  183. //Iterate through our assetList to find the compliant entry in our matList
  184. for (U32 m = 0; m < mMeshAsset->getMaterialCount(); m++)
  185. {
  186. AssetPtr<MaterialAsset> matAsset = mMeshAsset->getMaterialAsset(m);
  187. if (matAsset->getMaterialDefinitionName() == materialname)
  188. {
  189. dSprintf(matFieldName, 128, "MaterialSlot%d", i);
  190. addComponentField(matFieldName, "A material used in the shape file", "Material", matAsset->getAssetId(), "");
  191. break;
  192. }
  193. }
  194. }
  195. if (materialCount > 0)
  196. mComponentGroup = "";
  197. }
  198. if (mOwner != NULL)
  199. {
  200. Point3F min, max, pos;
  201. pos = mOwner->getPosition();
  202. mOwner->getWorldToObj().mulP(pos);
  203. min = mMeshAsset->getShape()->mBounds.minExtents;
  204. max = mMeshAsset->getShape()->mBounds.maxExtents;
  205. if (mInterfaceData)
  206. {
  207. mInterfaceData->mBounds.set(min, max);
  208. mInterfaceData->mScale = mOwner->getScale();
  209. mInterfaceData->mTransform = mOwner->getRenderTransform();
  210. }
  211. mOwner->setObjectBox(Box3F(min, max));
  212. mOwner->resetWorldBox();
  213. if (mOwner->getSceneManager() != NULL)
  214. mOwner->getSceneManager()->notifyObjectDirty(mOwner);
  215. }
  216. //finally, notify that our shape was changed
  217. onShapeInstanceChanged.trigger(this);
  218. }
  219. }
  220. void MeshComponent::setupShape()
  221. {
  222. mInterfaceData->mShapeInstance = new TSShapeInstance(mMeshAsset->getShape(), true);
  223. }
  224. void MeshComponent::_onResourceChanged( const Torque::Path &path )
  225. {
  226. /*bool srv = isServerObject();
  227. if (mInterfaceData == nullptr)
  228. return;
  229. String filePath;
  230. if (mMeshAsset)
  231. filePath = Torque::Path(mMeshAsset->getShapeFilename());
  232. if (!mMeshAsset || path != Torque::Path(mMeshAsset->getShapeFilename()) )
  233. return;
  234. updateShape();
  235. setMaskBits(ShapeMask);*/
  236. }
  237. void MeshComponent::inspectPostApply()
  238. {
  239. Parent::inspectPostApply();
  240. }
  241. U32 MeshComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  242. {
  243. U32 retMask = Parent::packUpdate(con, mask, stream);
  244. if (!mOwner || con->getGhostIndex(mOwner) == -1)
  245. {
  246. stream->writeFlag(false);
  247. stream->writeFlag(false);
  248. if (mask & ShapeMask)
  249. retMask |= ShapeMask;
  250. if (mask & MaterialMask)
  251. retMask |= MaterialMask;
  252. return retMask;
  253. }
  254. if (stream->writeFlag(mask & ShapeMask))
  255. {
  256. stream->writeString(mShapeName);
  257. }
  258. if (stream->writeFlag( mask & MaterialMask ))
  259. {
  260. stream->writeInt(mChangingMaterials.size(), 16);
  261. for(U32 i=0; i < mChangingMaterials.size(); i++)
  262. {
  263. stream->writeInt(mChangingMaterials[i].slot, 16);
  264. NetStringHandle matNameStr = mChangingMaterials[i].assetId.c_str();
  265. con->packNetStringHandleU(stream, matNameStr);
  266. }
  267. mChangingMaterials.clear();
  268. }
  269. return retMask;
  270. }
  271. void MeshComponent::unpackUpdate(NetConnection *con, BitStream *stream)
  272. {
  273. Parent::unpackUpdate(con, stream);
  274. if(stream->readFlag())
  275. {
  276. mShapeName = stream->readSTString();
  277. setMeshAsset(mShapeName);
  278. updateShape();
  279. }
  280. if(stream->readFlag())
  281. {
  282. mChangingMaterials.clear();
  283. U32 materialCount = stream->readInt(16);
  284. for(U32 i=0; i < materialCount; i++)
  285. {
  286. matMap newMatMap;
  287. newMatMap.slot = stream->readInt(16);
  288. newMatMap.assetId = String(con->unpackNetStringHandleU(stream).getString());
  289. //do the lookup, now
  290. newMatMap.matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newMatMap.assetId);
  291. mChangingMaterials.push_back(newMatMap);
  292. }
  293. updateMaterials();
  294. }
  295. }
  296. void MeshComponent::prepRenderImage( SceneRenderState *state )
  297. {
  298. /*if (!mEnabled || !mOwner || !mShapeInstance)
  299. return;
  300. Point3F cameraOffset;
  301. mOwner->getRenderTransform().getColumn(3, &cameraOffset);
  302. cameraOffset -= state->getDiffuseCameraPosition();
  303. F32 dist = cameraOffset.len();
  304. if (dist < 0.01f)
  305. dist = 0.01f;
  306. Point3F objScale = getOwner()->getScale();
  307. F32 invScale = (1.0f / getMax(getMax(objScale.x, objScale.y), objScale.z));
  308. mShapeInstance->setDetailFromDistance(state, dist * invScale);
  309. if (mShapeInstance->getCurrentDetail() < 0)
  310. return;
  311. GFXTransformSaver saver;
  312. // Set up our TS render state.
  313. TSRenderState rdata;
  314. rdata.setSceneState(state);
  315. rdata.setFadeOverride(1.0f);
  316. rdata.setOriginSort(false);
  317. // We might have some forward lit materials
  318. // so pass down a query to gather lights.
  319. LightQuery query;
  320. query.init(mOwner->getWorldSphere());
  321. rdata.setLightQuery(&query);
  322. MatrixF mat = mOwner->getRenderTransform();
  323. if (mOwner->isMounted())
  324. {
  325. MatrixF wrldPos = mOwner->getWorldTransform();
  326. Point3F wrldPosPos = wrldPos.getPosition();
  327. Point3F mntPs = mat.getPosition();
  328. EulerF mntRt = RotationF(mat).asEulerF();
  329. bool tr = true;
  330. }
  331. mat.scale(objScale);
  332. GFX->setWorldMatrix(mat);
  333. mShapeInstance->render(rdata);*/
  334. }
  335. void MeshComponent::updateMaterials()
  336. {
  337. if (mChangingMaterials.empty() || !mMeshAsset->getShape())
  338. return;
  339. TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
  340. pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
  341. bool found = false;
  342. const Vector<String> &materialNames = pMatList->getMaterialNameList();
  343. for ( S32 i = 0; i < materialNames.size(); i++ )
  344. {
  345. if (found)
  346. break;
  347. for(U32 m=0; m < mChangingMaterials.size(); m++)
  348. {
  349. if(mChangingMaterials[m].slot == i)
  350. {
  351. //Fetch the actual material asset
  352. pMatList->renameMaterial( i, mChangingMaterials[m].matAsset->getMaterialDefinitionName());
  353. found = true;
  354. break;
  355. }
  356. }
  357. }
  358. mChangingMaterials.clear();
  359. // Initialize the material instances
  360. mInterfaceData->mShapeInstance->initMaterialList();
  361. }
  362. MatrixF MeshComponent::getNodeTransform(S32 nodeIdx)
  363. {
  364. if (mInterfaceData != nullptr && !mMeshAsset.isNull() && mMeshAsset->isAssetValid() && mMeshAsset->getShape())
  365. {
  366. S32 nodeCount = getShape()->nodes.size();
  367. if(nodeIdx >= 0 && nodeIdx < nodeCount)
  368. {
  369. //animate();
  370. MatrixF nodeTransform = mInterfaceData->mShapeInstance->mNodeTransforms[nodeIdx];
  371. const Point3F& scale = mOwner->getScale();
  372. // The position of the node needs to be scaled.
  373. Point3F position = nodeTransform.getPosition();
  374. position.convolve(scale);
  375. nodeTransform.setPosition(position);
  376. MatrixF finalTransform = MatrixF::Identity;
  377. finalTransform.mul(mOwner->getRenderTransform(), nodeTransform);
  378. return finalTransform;
  379. }
  380. }
  381. return MatrixF::Identity;
  382. }
  383. S32 MeshComponent::getNodeByName(String nodeName)
  384. {
  385. if (mMeshAsset->getShape())
  386. {
  387. S32 nodeIdx = getShape()->findNode(nodeName);
  388. return nodeIdx;
  389. }
  390. return -1;
  391. }
  392. bool MeshComponent::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info)
  393. {
  394. return false;
  395. }
  396. void MeshComponent::mountObjectToNode(SceneObject* objB, String node, MatrixF txfm)
  397. {
  398. const char* test;
  399. test = node.c_str();
  400. if(dIsdigit(test[0]))
  401. {
  402. getOwner()->mountObject(objB, dAtoi(node), txfm);
  403. }
  404. else
  405. {
  406. if(TSShape* shape = getShape())
  407. {
  408. S32 idx = shape->findNode(node);
  409. getOwner()->mountObject(objB, idx, txfm);
  410. }
  411. }
  412. }
  413. void MeshComponent::onDynamicModified(const char* slotName, const char* newValue)
  414. {
  415. if(FindMatch::isMatch( "materialslot*", slotName, false ))
  416. {
  417. if(!getShape())
  418. return;
  419. S32 slot = -1;
  420. String outStr( String::GetTrailingNumber( slotName, slot ) );
  421. if(slot == -1)
  422. return;
  423. //Safe to assume the inbound value for the material will be a MaterialAsset, so lets do a lookup on the name
  424. MaterialAsset* matAsset = AssetDatabase.acquireAsset<MaterialAsset>(newValue);
  425. if (!matAsset)
  426. return;
  427. bool found = false;
  428. for(U32 i=0; i < mChangingMaterials.size(); i++)
  429. {
  430. if(mChangingMaterials[i].slot == slot)
  431. {
  432. mChangingMaterials[i].matAsset = matAsset;
  433. mChangingMaterials[i].assetId = newValue;
  434. found = true;
  435. }
  436. }
  437. if(!found)
  438. {
  439. matMap newMatMap;
  440. newMatMap.slot = slot;
  441. newMatMap.matAsset = matAsset;
  442. newMatMap.assetId = newValue;
  443. mChangingMaterials.push_back(newMatMap);
  444. }
  445. setMaskBits(MaterialMask);
  446. }
  447. Parent::onDynamicModified(slotName, newValue);
  448. }
  449. void MeshComponent::changeMaterial(U32 slot, MaterialAsset* newMat)
  450. {
  451. char fieldName[512];
  452. //update our respective field
  453. dSprintf(fieldName, 512, "materialSlot%d", slot);
  454. setDataField(fieldName, NULL, newMat->getAssetId());
  455. }
  456. bool MeshComponent::setMatInstField(U32 slot, const char* field, const char* value)
  457. {
  458. TSMaterialList* pMatList = mInterfaceData->mShapeInstance->getMaterialList();
  459. pMatList->setTextureLookupPath(getShapeResource().getPath().getPath());
  460. MaterialParameters* params = pMatList->getMaterialInst(slot)->getMaterialParameters();
  461. if (pMatList->getMaterialInst(slot)->getFeatures().hasFeature(MFT_DiffuseColor))
  462. {
  463. MaterialParameterHandle* handle = pMatList->getMaterialInst(slot)->getMaterialParameterHandle("DiffuseColor");
  464. params->set(handle, LinearColorF(0, 0, 0));
  465. }
  466. return true;
  467. }
  468. void MeshComponent::onInspect()
  469. {
  470. }
  471. void MeshComponent::onEndInspect()
  472. {
  473. }
  474. void MeshComponent::ownerTransformSet(MatrixF *mat)
  475. {
  476. if (mInterfaceData != nullptr)
  477. {
  478. MatrixF newTransform = *mat;
  479. mInterfaceData->mTransform = newTransform;
  480. }
  481. }