ModelDef.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. #include "ModelDef.h"
  2. #include "BFApp.h"
  3. #include "gfx/RenderDevice.h"
  4. #include "gfx/ModelInstance.h"
  5. #include "util/Dictionary.h"
  6. #include "util/TLSingleton.h"
  7. #include "FileStream.h"
  8. #include "MemStream.h"
  9. #include "util/MathUtils.h"
  10. #include "util/Sphere.h"
  11. #include "util/HashSet.h"
  12. #include "util/BeefPerf.h"
  13. #pragma warning(disable:4190)
  14. USING_NS_BF;
  15. struct ModelManager
  16. {
  17. public:
  18. Dictionary<String, ModelMaterialDef*> mMaterialMap;
  19. };
  20. ModelManager sModelManager;
  21. static TLSingleton<String> gModelDef_TLStrReturn;
  22. void Beefy::ModelAnimation::GetJointTranslation(int jointIdx, float frameNum, ModelJointTranslation* outJointTranslation)
  23. {
  24. // Frame 35
  25. BF_ASSERT((int)frameNum < (int)mFrames.size());
  26. int frameNumStart = (int)frameNum;
  27. int frameNumEnd = (frameNumStart + 1) % (int)mFrames.size();
  28. float endAlpha = frameNum - frameNumStart;
  29. float startAlpha = 1.0f - endAlpha;
  30. ModelJointTranslation* jointTransStart = &(mFrames[frameNumStart].mJointTranslations[jointIdx]);
  31. ModelJointTranslation* jointTransEnd = &(mFrames[frameNumEnd].mJointTranslations[jointIdx]);
  32. //if (/*(jointIdx == 37) || (jointIdx == 36) || (jointIdx == 35) ||*/ (jointIdx == 34) /*|| (jointIdx == 12) || (jointIdx == 11) || (jointIdx == 10) || (jointIdx == 0)*/)
  33. {
  34. outJointTranslation->mQuat = Quaternion::Slerp(endAlpha, jointTransStart->mQuat, jointTransEnd->mQuat, true);
  35. outJointTranslation->mScale = (jointTransStart->mScale * startAlpha) + (jointTransEnd->mScale * endAlpha);
  36. outJointTranslation->mTrans = (jointTransStart->mTrans * startAlpha) + (jointTransEnd->mTrans * endAlpha);
  37. }
  38. /*else
  39. {
  40. *outJointTranslation = *jointTransStart;
  41. }*/
  42. //*outJointTranslation = *jointTransStart;
  43. }
  44. //
  45. BF_EXPORT ModelInstance* BF_CALLTYPE ModelDef_CreateModelInstance(ModelDef* modelDef, ModelCreateFlags flags)
  46. {
  47. return gBFApp->mRenderDevice->CreateModelInstance(modelDef, flags);
  48. }
  49. BF_EXPORT void ModelDef_Compact(ModelDef* modelDef)
  50. {
  51. modelDef->Compact();
  52. }
  53. BF_EXPORT void ModelDef_GetBounds(ModelDef* modelDef, Vector3& min, Vector3& max)
  54. {
  55. modelDef->GetBounds(min, max);
  56. }
  57. BF_EXPORT void ModelDef_SetBaseDir(ModelDef* modelDef, char* baseDIr)
  58. {
  59. modelDef->mLoadDir = baseDIr;
  60. }
  61. BF_EXPORT const char* BF_CALLTYPE ModelDef_GetInfo(ModelDef* modelDef)
  62. {
  63. String& outString = *gModelDef_TLStrReturn.Get();
  64. outString.Clear();
  65. for (int meshIdx = 0; meshIdx < (int)modelDef->mMeshes.mSize; meshIdx++)
  66. {
  67. auto mesh = modelDef->mMeshes[meshIdx];
  68. for (int primIdx = 0; primIdx < (int)mesh.mPrimitives.mSize; primIdx++)
  69. {
  70. auto prims = mesh.mPrimitives[primIdx];
  71. outString += StrFormat("%d\t%d\t%d\t%d", meshIdx, primIdx, prims.mIndices.size(), prims.mVertices.size());
  72. for (auto& texPath : prims.mTexPaths)
  73. {
  74. outString += "\t";
  75. outString += texPath;
  76. }
  77. outString += "\n";
  78. }
  79. }
  80. return outString.c_str();
  81. }
  82. BF_EXPORT float BF_CALLTYPE ModelDef_GetFrameRate(ModelDef* modelDef)
  83. {
  84. return modelDef->mFrameRate;
  85. }
  86. BF_EXPORT int BF_CALLTYPE ModelDef_GetJointCount(ModelDef* modelDef)
  87. {
  88. return (int)modelDef->mJoints.size();
  89. }
  90. BF_EXPORT int BF_CALLTYPE ModelDef_GetAnimCount(ModelDef* modelDef)
  91. {
  92. return (int)modelDef->mAnims.size();
  93. }
  94. BF_EXPORT ModelAnimation* BF_CALLTYPE ModelDef_GetAnimation(ModelDef* modelDef, int animIdx)
  95. {
  96. return &modelDef->mAnims[animIdx];
  97. }
  98. BF_EXPORT void BF_CALLTYPE ModelDef_SetTextures(ModelDef* modelDef, int32 meshIdx, int32 primitivesIdx, char** paths, int32 pathCount)
  99. {
  100. auto& prims = modelDef->mMeshes[meshIdx].mPrimitives[primitivesIdx];
  101. prims.mTexPaths.Clear();
  102. for (int i = 0; i < pathCount; i++)
  103. prims.mTexPaths.Add(paths[i]);
  104. }
  105. BF_EXPORT bool BF_CALLTYPE ModelDef_RayIntersect(ModelDef* modelDef, const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
  106. {
  107. return modelDef->RayIntersect(worldMtx, origin, vec, outIntersect, outDistance);
  108. }
  109. BF_EXPORT void BF_CALLTYPE ModelDefAnimation_GetJointTranslation(ModelAnimation* modelAnimation, int jointIdx, float frame, ModelJointTranslation* outJointTranslation)
  110. {
  111. modelAnimation->GetJointTranslation(jointIdx, frame, outJointTranslation);
  112. }
  113. BF_EXPORT int BF_CALLTYPE ModelDefAnimation_GetFrameCount(ModelAnimation* modelAnimation)
  114. {
  115. return (int)modelAnimation->mFrames.size();
  116. }
  117. BF_EXPORT const char* BF_CALLTYPE ModelDefAnimation_GetName(ModelAnimation* modelAnimation)
  118. {
  119. return modelAnimation->mName.c_str();
  120. }
  121. BF_EXPORT void BF_CALLTYPE ModelDefAnimation_Clip(ModelAnimation* modelAnimation, int startFrame, int numFrames)
  122. {
  123. modelAnimation->mFrames.RemoveRange(0, startFrame);
  124. modelAnimation->mFrames.RemoveRange(numFrames, modelAnimation->mFrames.Count() - numFrames);
  125. }
  126. ModelDef::ModelDef()
  127. {
  128. mFlags = Flags_None;
  129. }
  130. ModelDef::~ModelDef()
  131. {
  132. for (auto& materialInstance : mMaterials)
  133. {
  134. materialInstance.mDef->mRefCount--;
  135. }
  136. }
  137. void ModelDef::Compact()
  138. {
  139. for (auto& mesh : mMeshes)
  140. {
  141. for (auto& prims : mesh.mPrimitives)
  142. {
  143. Array<int> vtxMap;
  144. vtxMap.Insert(0, -1, prims.mVertices.mSize);
  145. int newVtxIdx = 0;
  146. for (uint16 vtxIdx : prims.mIndices)
  147. {
  148. if (vtxMap[vtxIdx] == -1)
  149. vtxMap[vtxIdx] = newVtxIdx++;
  150. }
  151. if (newVtxIdx >= prims.mVertices.mSize)
  152. continue;
  153. for (uint16& vtxIdx : prims.mIndices)
  154. vtxIdx = vtxMap[vtxIdx];
  155. Array<ModelVertex> oldVertices = prims.mVertices;
  156. prims.mVertices.Resize(newVtxIdx);
  157. for (int oldVtxIdx = 0; oldVtxIdx < oldVertices.mSize; oldVtxIdx++)
  158. {
  159. int newVtxIdx = vtxMap[oldVtxIdx];
  160. if (newVtxIdx != -1)
  161. prims.mVertices[newVtxIdx] = oldVertices[oldVtxIdx];
  162. }
  163. }
  164. }
  165. }
  166. void ModelDef::CalcBounds()
  167. {
  168. int vtxCount = 0;
  169. for (auto& mesh : mMeshes)
  170. {
  171. for (auto& prims : mesh.mPrimitives)
  172. {
  173. for (auto& vtx : prims.mVertices)
  174. {
  175. if (vtxCount == 0)
  176. {
  177. mBounds.mMin = vtx.mPosition;
  178. mBounds.mMax = vtx.mPosition;
  179. }
  180. else
  181. {
  182. mBounds.mMin.mX = BF_MIN(mBounds.mMin.mX, vtx.mPosition.mX);
  183. mBounds.mMin.mY = BF_MIN(mBounds.mMin.mY, vtx.mPosition.mY);
  184. mBounds.mMin.mZ = BF_MIN(mBounds.mMin.mZ, vtx.mPosition.mZ);
  185. mBounds.mMax.mX = BF_MAX(mBounds.mMax.mX, vtx.mPosition.mX);
  186. mBounds.mMax.mY = BF_MAX(mBounds.mMax.mY, vtx.mPosition.mY);
  187. mBounds.mMax.mZ = BF_MAX(mBounds.mMax.mZ, vtx.mPosition.mZ);
  188. }
  189. vtxCount++;
  190. }
  191. }
  192. }
  193. mFlags = (Flags)(mFlags | Flags_HasBounds);
  194. }
  195. void ModelDef::GetBounds(Vector3& min, Vector3& max)
  196. {
  197. if ((mFlags & Flags_HasBounds) == 0)
  198. CalcBounds();
  199. min = mBounds.mMin;
  200. max = mBounds.mMax;
  201. }
  202. #define SWAP(x, y) { auto temp = x; x = y; y = temp; }
  203. #define N (sizeof(A)/sizeof(A[0]))
  204. // Partition using Lomuto partition scheme
  205. static int partition(float a[], int left, int right, int pIndex)
  206. {
  207. // pick `pIndex` as a pivot from the array
  208. float pivot = a[pIndex];
  209. // Move pivot to end
  210. SWAP(a[pIndex], a[right]);
  211. // elements less than the pivot will be pushed to the left of `pIndex`;
  212. // elements more than the pivot will be pushed to the right of `pIndex`;
  213. // equal elements can go either way
  214. pIndex = left;
  215. // each time we find an element less than or equal to the pivot, `pIndex`
  216. // is incremented, and that element would be placed before the pivot.
  217. for (int i = left; i < right; i++)
  218. {
  219. if (a[i] <= pivot)
  220. {
  221. SWAP(a[i], a[pIndex]);
  222. pIndex++;
  223. }
  224. }
  225. // move pivot to its final place
  226. SWAP(a[pIndex], a[right]);
  227. // return `pIndex` (index of the pivot element)
  228. return pIndex;
  229. }
  230. // Returns the k'th smallest element in the list within `left…right`
  231. // (i.e., `left <= k <= right`). The search space within the array is
  232. // changing for each round – but the list is still the same size.
  233. // Thus, `k` does not need to be updated with each round.
  234. static float quickselect(float A[], int left, int right, int k)
  235. {
  236. // If the array contains only one element, return that element
  237. if (left == right) {
  238. return A[left];
  239. }
  240. // select `pIndex` between left and right
  241. int pIndex = left + rand() % (right - left + 1);
  242. pIndex = partition(A, left, right, pIndex);
  243. // The pivot is in its final sorted position
  244. if (k == pIndex) {
  245. return A[k];
  246. }
  247. // if `k` is less than the pivot index
  248. else if (k < pIndex) {
  249. return quickselect(A, left, pIndex - 1, k);
  250. }
  251. // if `k` is more than the pivot index
  252. else {
  253. return quickselect(A, pIndex + 1, right, k);
  254. }
  255. }
  256. void ModelDef::GenerateCollisionData()
  257. {
  258. BP_ZONE("ModelDef::GenerateCollisionData");
  259. mFlags = (Flags)(mFlags | Flags_HasBVH);
  260. int statsWorkItrs = 0;
  261. int statsWorkTris = 0;
  262. BF_ASSERT(mBVNodes.IsEmpty());
  263. struct _WorkEntry
  264. {
  265. int mParentNodeIdx;
  266. int mTriWorkIdx;
  267. int mTriWorkCount;
  268. };
  269. Array<int32> triWorkList;
  270. int triCount = 0;
  271. for (auto& mesh : mMeshes)
  272. {
  273. for (auto& prims : mesh.mPrimitives)
  274. {
  275. int startIdx = mBVIndices.mSize;
  276. triCount += prims.mIndices.mSize / 3;
  277. triWorkList.Reserve(triWorkList.mSize + triCount);
  278. mBVIndices.Reserve(mBVIndices.mSize + prims.mIndices.mSize);
  279. mBVVertices.Reserve(mBVVertices.mSize + prims.mVertices.mSize);
  280. for (int triIdx = 0; triIdx < triCount; triIdx++)
  281. triWorkList.Add(startIdx / 3 + triIdx);
  282. for (auto idx : prims.mIndices)
  283. {
  284. mBVIndices.Add(idx + startIdx);
  285. }
  286. for (auto& vtx : prims.mVertices)
  287. mBVVertices.Add(vtx.mPosition);
  288. }
  289. }
  290. Array<_WorkEntry> workList;
  291. _WorkEntry workEntry;
  292. workEntry.mParentNodeIdx = -1;
  293. workEntry.mTriWorkIdx = 0;
  294. workEntry.mTriWorkCount = triWorkList.mSize;
  295. workList.Add(workEntry);
  296. Array<Vector3> points;
  297. points.Reserve(triWorkList.mSize);
  298. Array<float> centers;
  299. centers.Reserve(triWorkList.mSize);
  300. Array<int> left;
  301. left.Reserve(triWorkList.mSize);
  302. Array<int> right;
  303. right.Reserve(triWorkList.mSize);
  304. mBVTris.Reserve(triWorkList.mSize * 2);
  305. while (!workList.IsEmpty())
  306. {
  307. auto workEntry = workList.back();
  308. workList.pop_back();
  309. statsWorkItrs++;
  310. statsWorkTris += workEntry.mTriWorkCount;
  311. centers.Clear();
  312. left.Clear();
  313. right.Clear();
  314. int nodeIdx = mBVNodes.mSize;
  315. mBVNodes.Add(ModelBVNode());
  316. if (workEntry.mParentNodeIdx != -1)
  317. {
  318. auto& bvParent = mBVNodes[workEntry.mParentNodeIdx];
  319. if (bvParent.mLeft == -1)
  320. bvParent.mLeft = nodeIdx;
  321. else
  322. {
  323. BF_ASSERT(bvParent.mRight == -1);
  324. bvParent.mRight = nodeIdx;
  325. }
  326. }
  327. for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
  328. {
  329. bool inLeft = false;
  330. bool inRight = false;
  331. int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
  332. for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
  333. {
  334. int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
  335. bool isNewVtx = false;
  336. int32* valuePtr = NULL;
  337. auto& vtx = mBVVertices[vtxIdx];
  338. auto& bvNode = mBVNodes[nodeIdx];
  339. if ((triIdxIdx == 0) && (triVtxIdx == 0))
  340. {
  341. bvNode.mBoundAABB.mMin = vtx;
  342. bvNode.mBoundAABB.mMax = vtx;
  343. }
  344. else
  345. {
  346. bvNode.mBoundAABB.mMin.mX = BF_MIN(bvNode.mBoundAABB.mMin.mX, vtx.mX);
  347. bvNode.mBoundAABB.mMin.mY = BF_MIN(bvNode.mBoundAABB.mMin.mY, vtx.mY);
  348. bvNode.mBoundAABB.mMin.mZ = BF_MIN(bvNode.mBoundAABB.mMin.mZ, vtx.mZ);
  349. bvNode.mBoundAABB.mMax.mX = BF_MAX(bvNode.mBoundAABB.mMax.mX, vtx.mX);
  350. bvNode.mBoundAABB.mMax.mY = BF_MAX(bvNode.mBoundAABB.mMax.mY, vtx.mY);
  351. bvNode.mBoundAABB.mMax.mZ = BF_MAX(bvNode.mBoundAABB.mMax.mZ, vtx.mZ);
  352. }
  353. }
  354. }
  355. //mBVNodes[nodeIdx].mBoundSphere = Sphere::MiniBall(points.mVals, points.mSize);
  356. bool didSplit = false;
  357. if (workEntry.mTriWorkCount > 4)
  358. {
  359. int splitPlane = 0;
  360. float splitWidth = 0;
  361. // Split along widest AABB dimension
  362. for (int dimIdx = 0; dimIdx < 3; dimIdx++)
  363. {
  364. float minVal = 0;
  365. float maxVal = 0;
  366. for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
  367. {
  368. int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
  369. for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
  370. {
  371. int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
  372. const Vector3& vtx = mBVVertices.mVals[vtxIdx];
  373. float coord = ((float*)&vtx)[dimIdx];
  374. if ((triIdxIdx == 0) && (triVtxIdx == 0))
  375. {
  376. minVal = coord;
  377. maxVal = coord;
  378. }
  379. else
  380. {
  381. minVal = BF_MIN(minVal, coord);
  382. maxVal = BF_MAX(maxVal, coord);
  383. }
  384. }
  385. }
  386. float width = maxVal - minVal;
  387. if (width > splitWidth)
  388. {
  389. splitPlane = dimIdx;
  390. splitWidth = width;
  391. }
  392. }
  393. centers.SetSize(workEntry.mTriWorkCount);
  394. for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
  395. {
  396. int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
  397. float coordAcc = 0;
  398. for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
  399. {
  400. int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
  401. const Vector3& vtx = mBVVertices.mVals[vtxIdx];
  402. float coord = ((float*)&vtx)[splitPlane];
  403. coordAcc += coord;
  404. }
  405. float coordAvg = coordAcc / 3;
  406. centers.mVals[triIdxIdx] = coordAvg;
  407. }
  408. float centerCoord = quickselect(centers.mVals, 0, centers.mSize - 1, centers.mSize / 2);
  409. // centers.Sort([](float lhs, float rhs) { return lhs < rhs; });
  410. // centerCoord = centers[centers.mSize / 2];
  411. for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
  412. {
  413. bool inLeft = false;
  414. bool inRight = false;
  415. int triIdx = triWorkList.mVals[workEntry.mTriWorkIdx + triIdxIdx];
  416. for (int triVtxIdx = 0; triVtxIdx < 3; triVtxIdx++)
  417. {
  418. int vtxIdx = mBVIndices.mVals[triIdx * 3 + triVtxIdx];
  419. const Vector3& vtx = mBVVertices.mVals[vtxIdx];
  420. float coord = ((float*)&vtx)[splitPlane];
  421. if (coord < centerCoord)
  422. inLeft = true;
  423. else
  424. inRight = true;
  425. }
  426. if (inLeft)
  427. left.Add(triIdx);
  428. if (inRight)
  429. right.Add(triIdx);
  430. }
  431. // Don't split if the split didn't significantly separate the triangles
  432. bool doSplit =
  433. (left.mSize <= workEntry.mTriWorkCount * 0.85f) &&
  434. (right.mSize <= workEntry.mTriWorkCount * 0.85f);
  435. if (doSplit)
  436. {
  437. mBVNodes[nodeIdx].mKind = ModelBVNode::Kind_Branch;
  438. mBVNodes[nodeIdx].mLeft = -1;
  439. mBVNodes[nodeIdx].mRight = -1;
  440. _WorkEntry childWorkEntry;
  441. childWorkEntry.mParentNodeIdx = nodeIdx;
  442. childWorkEntry.mTriWorkIdx = triWorkList.mSize;
  443. childWorkEntry.mTriWorkCount = right.mSize;
  444. workList.Add(childWorkEntry);
  445. triWorkList.Insert(triWorkList.mSize, right.mVals, right.mSize);
  446. childWorkEntry.mParentNodeIdx = nodeIdx;
  447. childWorkEntry.mTriWorkIdx = triWorkList.mSize;
  448. childWorkEntry.mTriWorkCount = left.mSize;
  449. workList.Add(childWorkEntry);
  450. triWorkList.Insert(triWorkList.mSize, left.mVals, left.mSize);
  451. continue;
  452. }
  453. }
  454. // Did not split
  455. int triStartIdx = mBVTris.mSize;
  456. //mBVTris.Reserve(mBVTris.mSize + workEntry.mTriWorkCount);
  457. for (int triIdxIdx = 0; triIdxIdx < workEntry.mTriWorkCount; triIdxIdx++)
  458. mBVTris.Add(triWorkList[workEntry.mTriWorkIdx + triIdxIdx]);
  459. auto& bvNode = mBVNodes[nodeIdx];
  460. bvNode.mKind = ModelBVNode::Kind_Leaf;
  461. bvNode.mTriStartIdx = triStartIdx;
  462. bvNode.mTriCount = workEntry.mTriWorkCount;
  463. }
  464. NOP;
  465. }
  466. void ModelDef::RayIntersect(ModelBVNode* bvNode, const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
  467. {
  468. // if (!RayIntersectsCircle(origin, vec, bvNode->mBoundSphere, NULL, NULL, NULL))
  469. // return false;
  470. if (!RayIntersectsAABB(origin, vec, bvNode->mBoundAABB, NULL, NULL, NULL))
  471. return;
  472. if (bvNode->mKind == ModelBVNode::Kind_Branch)
  473. {
  474. bool hadIntersect = false;
  475. for (int branchIdx = 0; branchIdx < 2; branchIdx++)
  476. RayIntersect(&mBVNodes[(branchIdx == 0) ? bvNode->mLeft : bvNode->mRight], worldMtx, origin, vec, outIntersect, outDistance);
  477. return;
  478. }
  479. for (int triIdxIdx = 0; triIdxIdx < bvNode->mTriCount; triIdxIdx++)
  480. {
  481. int triIdx = mBVTris[bvNode->mTriStartIdx + triIdxIdx];
  482. Vector3 curIntersect;
  483. float curDistance;
  484. if (RayIntersectsTriangle(origin, vec,
  485. mBVVertices[mBVIndices[triIdx*3+0]], mBVVertices[mBVIndices[triIdx*3+1]], mBVVertices[mBVIndices[triIdx*3+2]],
  486. &curIntersect, &curDistance))
  487. {
  488. if (curDistance < outDistance)
  489. {
  490. outIntersect = curIntersect;
  491. outDistance = curDistance;
  492. }
  493. }
  494. }
  495. }
  496. bool ModelDef::RayIntersect(const Matrix4& worldMtx, const Vector3& origin, const Vector3& vec, Vector3& outIntersect, float& outDistance)
  497. {
  498. if ((mFlags & Flags_HasBounds) == 0)
  499. CalcBounds();
  500. if (!RayIntersectsAABB(origin, vec, mBounds, NULL, NULL, NULL))
  501. return false;
  502. if (mBVNodes.IsEmpty())
  503. GenerateCollisionData();
  504. const float maxDist = 3.40282e+038f;
  505. outDistance = maxDist;
  506. RayIntersect(&mBVNodes[0], worldMtx, origin, vec, outIntersect, outDistance);
  507. return outDistance != maxDist;
  508. }
  509. ModelMaterialDef* ModelMaterialDef::CreateOrGet(const StringImpl& prefix, const StringImpl& path)
  510. {
  511. StringT<128> key = prefix;
  512. key += ":";
  513. key += path;
  514. ModelMaterialDef** modelMaterialDefPtr = NULL;
  515. if (sModelManager.mMaterialMap.TryAdd(key, NULL, &modelMaterialDefPtr))
  516. *modelMaterialDefPtr = new ModelMaterialDef();
  517. return *modelMaterialDefPtr;
  518. }
  519. ///
  520. class ModelReader
  521. {
  522. public:
  523. ModelDef* mModelDef;
  524. DataStream* mFS;
  525. public:
  526. ModelReader(ModelDef* modelDef)
  527. {
  528. mFS = NULL;
  529. mModelDef = modelDef;
  530. }
  531. ~ModelReader()
  532. {
  533. delete mFS;
  534. }
  535. bool ReadFile()
  536. {
  537. int sig = mFS->ReadInt32();
  538. if (sig != 0xBEEF0001)
  539. return false;
  540. int flags = mFS->ReadInt32();
  541. Array<String> texNames;
  542. int texNameSize = mFS->ReadInt32();
  543. for (int i = 0; i < texNameSize; i++)
  544. {
  545. String path = mFS->ReadAscii32SizedString();
  546. texNames.Add(path);
  547. }
  548. int idxCount = mFS->ReadInt32();
  549. mModelDef->mMeshes.Add(ModelMesh());
  550. auto& modelMesh = mModelDef->mMeshes[0];
  551. modelMesh.mPrimitives.Add(ModelPrimitives());
  552. auto& modelPrimitives = modelMesh.mPrimitives[0];
  553. modelPrimitives.mFlags = (ModelPrimitives::Flags)flags;
  554. modelPrimitives.mTexPaths = texNames;
  555. modelPrimitives.mIndices.Resize(idxCount);
  556. mFS->Read(modelPrimitives.mIndices.mVals, idxCount * 2);
  557. int vtxCount = mFS->ReadInt32();
  558. modelPrimitives.mVertices.Resize(vtxCount);
  559. for (int i = 0; i < vtxCount; i++)
  560. {
  561. if ((flags & ModelPrimitives::Flags_Vertex_Position) != 0)
  562. mFS->ReadT(modelPrimitives.mVertices[i].mPosition);
  563. if ((flags & ModelPrimitives::Flags_Vertex_Tex0) != 0)
  564. mFS->ReadT(modelPrimitives.mVertices[i].mTexCoords);
  565. if ((flags & ModelPrimitives::Flags_Vertex_Tex1) != 0)
  566. mFS->ReadT(modelPrimitives.mVertices[i].mBumpTexCoords);
  567. }
  568. return true;
  569. }
  570. bool ReadFile(const StringImpl& fileName, const StringImpl& baseDir)
  571. {
  572. if (fileName.StartsWith('@'))
  573. {
  574. int colon = (int)fileName.IndexOf(':');
  575. String addrStr = fileName.Substring(1, colon - 1);
  576. String lenStr = fileName.Substring(colon + 1);
  577. void* addr = (void*)(intptr)strtoll(addrStr.c_str(), NULL, 16);
  578. int len = (int)strtol(lenStr.c_str(), NULL, 10);
  579. MemStream* memStream = new MemStream(addr, len, false);
  580. mFS = memStream;
  581. }
  582. else
  583. {
  584. FileStream* fs = new FileStream();
  585. mFS = fs;
  586. if (!fs->Open(fileName, "rb"))
  587. return false;
  588. }
  589. return ReadFile();
  590. }
  591. };
  592. BF_EXPORT void* BF_CALLTYPE Res_OpenModel(const char* fileName, const char* baseDir, void* vertexDefinition)
  593. {
  594. ModelDef* modelDef = new ModelDef();
  595. modelDef->mLoadDir = baseDir;
  596. ModelReader reader(modelDef);
  597. if (!reader.ReadFile(fileName, baseDir))
  598. {
  599. delete modelDef;
  600. return NULL;
  601. }
  602. return modelDef;
  603. }
  604. BF_EXPORT StringView BF_CALLTYPE Res_SerializeModel(ModelDef* modelDef)
  605. {
  606. DynMemStream ms;
  607. ms.Write((int)0xBEEF0001);
  608. for (auto& mesh : modelDef->mMeshes)
  609. {
  610. for (auto& prims : mesh.mPrimitives)
  611. {
  612. ms.Write((int)prims.mFlags);
  613. ms.Write(prims.mTexPaths.mSize);
  614. for (auto& path : prims.mTexPaths)
  615. ms.Write(path);
  616. ms.Write((int)prims.mIndices.mSize);
  617. ms.Write(prims.mIndices.mVals, prims.mIndices.mSize * 2);
  618. ms.Write((int)prims.mVertices.mSize);
  619. for (int i = 0; i < prims.mVertices.mSize; i++)
  620. {
  621. auto& vtx = prims.mVertices[i];
  622. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Position) != 0)
  623. ms.WriteT(vtx.mPosition);
  624. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tex0) != 0)
  625. ms.WriteT(vtx.mTexCoords);
  626. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tex1) != 0)
  627. ms.WriteT(vtx.mBumpTexCoords);
  628. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Color) != 0)
  629. ms.WriteT(vtx.mColor);
  630. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Normal) != 0)
  631. ms.WriteT(vtx.mNormal);
  632. if ((prims.mFlags & ModelPrimitives::Flags_Vertex_Tangent) != 0)
  633. ms.WriteT(vtx.mTangent);
  634. }
  635. }
  636. }
  637. String& outString = *gModelDef_TLStrReturn.Get();
  638. outString.Clear();
  639. outString.Append((char*)ms.GetPtr(), ms.GetSize());
  640. return outString;
  641. }