CustomObject.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "CustomObject.h"
  25. #include "Geometry.h"
  26. #include "IndexBuffer.h"
  27. #include "Log.h"
  28. #include "Material.h"
  29. #include "OcclusionBuffer.h"
  30. #include "OctreeQuery.h"
  31. #include "Profiler.h"
  32. #include "Renderer.h"
  33. #include "ResourceCache.h"
  34. #include "VertexBuffer.h"
  35. #include "XMLElement.h"
  36. #include <algorithm>
  37. #include <cstring>
  38. #include "DebugNew.h"
  39. static bool compareCustomGeometries(const CustomGeometry& lhs, const CustomGeometry& rhs)
  40. {
  41. return lhs.mMaterial.getPtr() < rhs.mMaterial.getPtr();
  42. }
  43. float CustomGeometry::getDistance(const Ray& ray) const
  44. {
  45. if ((!mVertexCount) || (!mIndexCount))
  46. return M_INFINITY;
  47. return ray.getDistance(mVertexData, mVertexSize, mIndexData, mIndexSize, 0, mIndexCount);
  48. }
  49. CustomObject::CustomObject(Octant* octant, const std::string& name) :
  50. GeometryNode(NODE_CUSTOMOBJECT, octant, name),
  51. mVertexElementMask(MASK_POSITION),
  52. mGeometriesDirty(false),
  53. mOptimization(true)
  54. {
  55. }
  56. CustomObject::~CustomObject()
  57. {
  58. }
  59. void CustomObject::save(Serializer& dest)
  60. {
  61. // Write GeometryNode properties
  62. GeometryNode::save(dest);
  63. // Write CustomObject properties
  64. dest.writeBool(mOptimization);
  65. dest.writeUInt(mVertexElementMask);
  66. dest.writeVLE(mCustomGeometries.size());
  67. unsigned vertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  68. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  69. {
  70. const CustomGeometry& geometry = mCustomGeometries[i];
  71. dest.writeStringHash(getResourceHash(geometry.mMaterial));
  72. dest.writeBoundingBox(geometry.mBoundingBox);
  73. dest.writeVLE(geometry.mVertexCount);
  74. dest.writeVLE(geometry.mIndexCount);
  75. dest.writeUByte(geometry.mIndexSize);
  76. unsigned vertexDataSize = geometry.mVertexCount * vertexSize;
  77. unsigned indexDataSize = geometry.mIndexCount * geometry.mIndexSize;
  78. if (vertexDataSize)
  79. dest.write(&geometry.mVertexData[0], vertexDataSize);
  80. if (indexDataSize)
  81. dest.write(&geometry.mIndexData[0], indexDataSize);
  82. }
  83. }
  84. void CustomObject::load(Deserializer& source, ResourceCache* cache)
  85. {
  86. // Read GeometryNode properties
  87. GeometryNode::load(source, cache);
  88. // Read CustomObject properties
  89. mOptimization = source.readBool();
  90. mVertexElementMask = source.readUInt();
  91. setNumGeometries(source.readVLE());
  92. unsigned vertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  93. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  94. {
  95. CustomGeometry& geometry = mCustomGeometries[i];
  96. geometry.mMaterial = cache->getResource<Material>(source.readStringHash());
  97. geometry.mBoundingBox = source.readBoundingBox();
  98. geometry.mVertexCount = source.readVLE();
  99. geometry.mIndexCount = source.readVLE();
  100. geometry.mIndexSize = source.readUByte();
  101. unsigned vertexDataSize = geometry.mVertexCount * vertexSize;
  102. unsigned indexDataSize = geometry.mIndexCount * geometry.mIndexSize;
  103. geometry.mVertexData = SharedArrayPtr<unsigned char>(new unsigned char[vertexDataSize]);
  104. geometry.mIndexData = SharedArrayPtr<unsigned char>(new unsigned char[indexDataSize]);
  105. source.read(&geometry.mVertexData[0], vertexDataSize);
  106. source.read(&geometry.mIndexData[0], indexDataSize);
  107. }
  108. }
  109. void CustomObject::saveXML(XMLElement& dest)
  110. {
  111. // Write GeometryNode properties
  112. GeometryNode::saveXML(dest);
  113. // Write CustomObject properties
  114. XMLElement geometriesElem = dest.createChildElement("geometries");
  115. geometriesElem.setBool("optimization", mOptimization);
  116. geometriesElem.setInt("elementmask", mVertexElementMask);
  117. geometriesElem.setInt("count", mCustomGeometries.size());
  118. unsigned vertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  119. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  120. {
  121. XMLElement geometryElem = dest.createChildElement("geometry");
  122. const CustomGeometry& geometry = mCustomGeometries[i];
  123. geometryElem.setBoundingBox(geometry.mBoundingBox);
  124. geometryElem.setString("materialname", getResourceName(geometry.mMaterial));
  125. geometryElem.setInt("vertexcount", geometry.mVertexCount);
  126. geometryElem.setInt("indexcount", geometry.mIndexCount);
  127. geometryElem.setInt("indexsize", geometry.mIndexSize);
  128. unsigned vertexDataSize = geometry.mVertexCount * vertexSize;
  129. unsigned indexDataSize = geometry.mIndexCount * geometry.mIndexSize;
  130. if (vertexDataSize)
  131. {
  132. XMLElement vertexDataElem = geometryElem.createChildElement("vertexdata");
  133. vertexDataElem.setBuffer("bytes", &geometry.mVertexData[0], vertexDataSize);
  134. }
  135. if (indexDataSize)
  136. {
  137. XMLElement indexDataElem = geometryElem.createChildElement("indexdata");
  138. indexDataElem.setBuffer("bytes", &geometry.mIndexData[0], indexDataSize);
  139. }
  140. }
  141. }
  142. void CustomObject::loadXML(const XMLElement& source, ResourceCache* cache)
  143. {
  144. // Read GeometryNode properties
  145. GeometryNode::loadXML(source, cache);
  146. // Read CustomObject properties
  147. XMLElement geometriesElem = source.getChildElement("geometries");
  148. mOptimization = geometriesElem.getBool("optimization");
  149. mVertexElementMask = geometriesElem.getInt("elementmask");
  150. setNumGeometries(geometriesElem.getInt("count"));
  151. unsigned vertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  152. XMLElement geometryElem = source.getChildElement("geometry");
  153. unsigned index = 0;
  154. while ((geometryElem) && (index < mGeometries.size()))
  155. {
  156. CustomGeometry& geometry = mCustomGeometries[index];
  157. geometry.mBoundingBox = geometryElem.getBoundingBox();
  158. geometry.mMaterial = cache->getResource<Material>(geometryElem.getString("materialname"));
  159. geometry.mVertexCount = geometryElem.getInt("vertexcount");
  160. geometry.mIndexCount = geometryElem.getInt("indexcount");
  161. geometry.mIndexSize = geometryElem.getInt("indexsize");
  162. unsigned vertexDataSize = geometry.mVertexCount * vertexSize;
  163. unsigned indexDataSize = geometry.mIndexCount * geometry.mIndexSize;
  164. geometry.mVertexData = SharedArrayPtr<unsigned char>(new unsigned char[vertexDataSize]);
  165. geometry.mIndexData = SharedArrayPtr<unsigned char>(new unsigned char[indexDataSize]);
  166. if (vertexDataSize)
  167. {
  168. XMLElement vertexDataElem = geometryElem.getChildElement("vertexdata");
  169. vertexDataElem.getBuffer("bytes", &geometry.mVertexData[0], vertexDataSize);
  170. }
  171. if (indexDataSize)
  172. {
  173. XMLElement indexDataElem = geometryElem.getChildElement("indexdata");
  174. indexDataElem.getBuffer("bytes", &geometry.mIndexData[0], indexDataSize);
  175. }
  176. geometryElem = geometryElem.getNextElement("geometry");
  177. ++index;
  178. }
  179. }
  180. void CustomObject::getResourceRefs(std::vector<Resource*>& dest)
  181. {
  182. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  183. {
  184. if (mCustomGeometries[i].mMaterial)
  185. dest.push_back(mCustomGeometries[i].mMaterial);
  186. }
  187. }
  188. void CustomObject::processRayQuery(RayOctreeQuery& query, float initialDistance)
  189. {
  190. PROFILE(CustomObject_Raycast);
  191. RayQueryLevel level = query.mLevel;
  192. const Matrix4x3& worldTransform = getWorldTransform();
  193. float nearest = M_INFINITY;
  194. unsigned nearestGeometry = 0;
  195. switch (level)
  196. {
  197. case RAY_AABB_NOSUBOBJECTS:
  198. {
  199. RayQueryResult result;
  200. result.mNode = this;
  201. result.mDistance = initialDistance;
  202. query.mResult.push_back(result);
  203. return;
  204. }
  205. case RAY_AABB:
  206. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  207. {
  208. const CustomGeometry& geom = mCustomGeometries[i];
  209. BoundingBox geometryBox = geom.mBoundingBox.getTransformed(worldTransform);
  210. float distance = geometryBox.getDistance(query.mRay);
  211. if ((distance < query.mMaxDistance) && (distance < nearest))
  212. {
  213. nearest = distance;
  214. nearestGeometry = i;
  215. }
  216. }
  217. break;
  218. case RAY_OBB:
  219. {
  220. Matrix4x3 inverse = worldTransform.getInverse();
  221. Ray localRay(inverse * query.mRay.mOrigin, inverse * Vector4(query.mRay.mDirection, 0.0f));
  222. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  223. {
  224. const CustomGeometry& geom = mCustomGeometries[i];
  225. float distance = geom.mBoundingBox.getDistance(localRay);
  226. if ((distance < query.mMaxDistance) && (distance < nearest))
  227. {
  228. nearest = distance;
  229. nearestGeometry = i;
  230. }
  231. }
  232. }
  233. break;
  234. case RAY_TRIANGLE:
  235. {
  236. Matrix4x3 inverse = worldTransform.getInverse();
  237. Ray localRay(inverse * query.mRay.mOrigin, inverse * Vector4(query.mRay.mDirection, 0.0f));
  238. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  239. {
  240. // Do an initial OBB test
  241. const CustomGeometry& geom = mCustomGeometries[i];
  242. float distance = geom.mBoundingBox.getDistance(localRay);
  243. if ((distance < query.mMaxDistance) && (distance < nearest))
  244. {
  245. // Then a triangle-level test
  246. distance = geom.getDistance(localRay);
  247. if ((distance < query.mMaxDistance) && (distance < nearest))
  248. {
  249. nearest = distance;
  250. nearestGeometry = i;
  251. }
  252. }
  253. }
  254. }
  255. break;
  256. }
  257. // Return the nearest hit against a geometry
  258. if (nearest < M_INFINITY)
  259. {
  260. RayQueryResult result;
  261. result.mNode = this;
  262. result.mDistance = nearest;
  263. result.mSubObject = nearestGeometry;
  264. query.mResult.push_back(result);
  265. }
  266. }
  267. void CustomObject::updateGeometry(const FrameInfo& frame, Renderer* renderer)
  268. {
  269. if (mGeometriesDirty)
  270. updateBuffer(renderer);
  271. }
  272. unsigned CustomObject::getNumBatches()
  273. {
  274. return mGeometries.size();
  275. }
  276. Geometry* CustomObject::getBatchGeometry(unsigned batchIndex)
  277. {
  278. return mGeometries[batchIndex];
  279. }
  280. Material* CustomObject::getBatchMaterial(unsigned batchIndex)
  281. {
  282. return mMaterials[batchIndex];
  283. }
  284. bool CustomObject::drawOcclusion(OcclusionBuffer* buffer)
  285. {
  286. bool success = true;
  287. for (unsigned i = 0; i < mGeometries.size(); ++i)
  288. {
  289. Geometry* geom = mGeometries[i];
  290. if (!geom)
  291. continue;
  292. // Check that the material is suitable for occlusion (default material always is)
  293. // and set culling mode
  294. Material* mat = mMaterials[i];
  295. if (mat)
  296. {
  297. if (!mat->getOcclusion())
  298. continue;
  299. buffer->setCullMode(mat->getOcclusionCullMode());
  300. }
  301. else
  302. buffer->setCullMode(CULL_CCW);
  303. const unsigned char* vertexData;
  304. unsigned vertexSize;
  305. const unsigned char* indexData;
  306. unsigned indexSize;
  307. geom->lockRawData(vertexData, vertexSize, indexData, indexSize);
  308. // Check for valid geometry data
  309. if ((!vertexData) || (!indexData))
  310. continue;
  311. unsigned indexStart = geom->getIndexStart();
  312. unsigned indexCount = geom->getIndexCount();
  313. // Draw and check for running out of triangles
  314. if (!buffer->draw(getWorldTransform(), vertexData, vertexSize, indexData, indexSize, indexStart, indexCount))
  315. success = false;
  316. geom->unlockRawData();
  317. if (!success)
  318. break;
  319. }
  320. return success;
  321. }
  322. bool CustomObject::setVertexElementMask(unsigned mask)
  323. {
  324. if (!(mask & MASK_POSITION))
  325. {
  326. LOGERROR("Custom object vertex data must contain positions");
  327. return false;
  328. }
  329. if (mask == mVertexElementMask)
  330. return true;
  331. mVertexElementMask = mask;
  332. // If geometries exist, clear their contents, but retain the amount
  333. unsigned numGeometries = mCustomGeometries.size();
  334. if (numGeometries)
  335. {
  336. mCustomGeometries.clear();
  337. mCustomGeometries.resize(numGeometries);
  338. mGeometriesDirty = true;
  339. }
  340. return true;
  341. }
  342. void CustomObject::setNumGeometries(unsigned num)
  343. {
  344. if (num != mCustomGeometries.size())
  345. {
  346. mCustomGeometries.resize(num);
  347. mGeometriesDirty = true;
  348. }
  349. }
  350. bool CustomObject::setGeometryData(unsigned index, const void* vertexData, unsigned vertexCount, const void* indexData, unsigned indexCount, bool largeIndices)
  351. {
  352. if (index >= mCustomGeometries.size())
  353. {
  354. LOGERROR("Illegal geometry index");
  355. return false;
  356. }
  357. CustomGeometry& geom = mCustomGeometries[index];
  358. geom.mVertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  359. if (vertexCount)
  360. {
  361. geom.mVertexData = new unsigned char[vertexCount * mVertexElementMask];
  362. geom.mVertexCount = vertexCount;
  363. memcpy(&geom.mVertexData[0], vertexData, vertexCount * geom.mVertexSize);
  364. geom.mBoundingBox.mDefined = false;
  365. for (unsigned i = 0; i < vertexCount; ++i)
  366. {
  367. Vector3 point((float*)&geom.mVertexData[i * geom.mVertexSize]);
  368. geom.mBoundingBox.merge(point);
  369. }
  370. }
  371. else
  372. {
  373. geom.mVertexData.reset();
  374. geom.mVertexCount = 0;
  375. }
  376. geom.mIndexSize = largeIndices ? sizeof(unsigned) : sizeof(unsigned short);
  377. geom.mIndexCount = indexCount;
  378. if (indexCount)
  379. {
  380. geom.mIndexData = new unsigned char[geom.mIndexCount * geom.mIndexSize];
  381. memcpy(&geom.mIndexData[0], indexData, geom.mIndexCount * geom.mIndexSize);
  382. }
  383. else
  384. geom.mIndexData.reset();
  385. calculateBoundingBox();
  386. mGeometriesDirty = true;
  387. return true;
  388. }
  389. void CustomObject::setMaterial(Material* material)
  390. {
  391. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  392. setMaterial(i, material);
  393. }
  394. bool CustomObject::setMaterial(unsigned index, Material* material)
  395. {
  396. if (index >= mCustomGeometries.size())
  397. {
  398. LOGERROR("Illegal material index");
  399. return false;
  400. }
  401. mCustomGeometries[index].mMaterial = material;
  402. if ((!mOptimization) && (!mGeometriesDirty) && (mMaterials.size() == mCustomGeometries.size()))
  403. mMaterials[index] = material;
  404. else
  405. mGeometriesDirty = true;
  406. return true;
  407. }
  408. void CustomObject::setOptimization(bool enable)
  409. {
  410. if (enable != mOptimization)
  411. {
  412. mOptimization = enable;
  413. mGeometriesDirty = true;
  414. }
  415. }
  416. const CustomGeometry* CustomObject::getGeometry(unsigned index) const
  417. {
  418. return index < mCustomGeometries.size() ? &mCustomGeometries[index] : (CustomGeometry*)0;
  419. }
  420. Material* CustomObject::getMaterial(unsigned index) const
  421. {
  422. return index < mCustomGeometries.size() ? mCustomGeometries[index].mMaterial : (Material*)0;
  423. }
  424. void CustomObject::onWorldBoundingBoxUpdate(BoundingBox& worldBoundingBox)
  425. {
  426. worldBoundingBox = mBoundingBox.getTransformed(getWorldTransform());
  427. }
  428. void CustomObject::calculateBoundingBox()
  429. {
  430. mBoundingBox.mMin = Vector3::sZero;
  431. mBoundingBox.mMax = Vector3::sZero;
  432. mBoundingBox.mDefined = false;
  433. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  434. {
  435. const CustomGeometry& geom = mCustomGeometries[i];
  436. if ((geom.mVertexCount) && (geom.mIndexCount))
  437. mBoundingBox.merge(geom.mBoundingBox);
  438. }
  439. VolumeNode::onMarkedDirty();
  440. }
  441. void CustomObject::updateBuffer(Renderer* renderer)
  442. {
  443. PROFILE(CustomObject_UpdateBuffer);
  444. if (!mVertexBuffer)
  445. mVertexBuffer = new VertexBuffer(renderer);
  446. if (!mIndexBuffer)
  447. mIndexBuffer = new IndexBuffer(renderer);
  448. unsigned totalVertexCount = 0;
  449. unsigned totalIndexCount = 0;
  450. mGeometries.clear();
  451. mMaterials.clear();
  452. std::vector<CustomGeometry>* customGeometries;
  453. static std::vector<CustomGeometry> sortedGeometries;
  454. if (mOptimization)
  455. {
  456. // For optimization to work, sort batches per material first
  457. sortedGeometries.resize(mCustomGeometries.size());
  458. sortedGeometries = mCustomGeometries;
  459. std::sort(sortedGeometries.begin(), sortedGeometries.end(), compareCustomGeometries);
  460. customGeometries = &sortedGeometries;
  461. }
  462. else
  463. customGeometries = &mCustomGeometries;
  464. for (unsigned i = 0; i < customGeometries->size(); ++i)
  465. {
  466. const CustomGeometry& src = (*customGeometries)[i];
  467. if ((!src.mVertexCount) || (!src.mIndexCount))
  468. continue;
  469. totalVertexCount += src.mVertexCount;
  470. totalIndexCount += src.mIndexCount;
  471. }
  472. // Use 16-bit indices if possible
  473. unsigned indexSize = totalVertexCount >= 65536 ? sizeof(unsigned) : sizeof(short);
  474. unsigned vertexCount = 0;
  475. unsigned indexCount = 0;
  476. mVertexBuffer->setSize(totalVertexCount, mVertexElementMask);
  477. mIndexBuffer->setSize(totalIndexCount, indexSize);
  478. unsigned char* vertexData = (unsigned char*)mVertexBuffer->lock(0, totalVertexCount, LOCK_NORMAL);
  479. unsigned char* indexData = (unsigned char*)mIndexBuffer->lock(0, totalIndexCount, LOCK_NORMAL);
  480. for (unsigned i = 0; i < customGeometries->size(); ++i)
  481. {
  482. const CustomGeometry& src = (*customGeometries)[i];
  483. if ((!src.mVertexCount) || (!src.mIndexCount))
  484. continue;
  485. SharedPtr<Geometry> dest;
  486. // If not optimized, build a new geometry for each batch
  487. // Otherwise check if the material is same, and expand the draw range in that case
  488. bool newGeometry = true;
  489. if ((mOptimization) && (mGeometries.size()) && (mMaterials.back() == src.mMaterial))
  490. newGeometry = false;
  491. if (newGeometry)
  492. {
  493. dest = new Geometry();
  494. dest->setIndexBuffer(mIndexBuffer);
  495. dest->setVertexBuffer(0, mVertexBuffer);
  496. dest->setDrawRange(TRIANGLE_LIST, indexCount, src.mIndexCount, vertexCount, src.mVertexCount);
  497. mGeometries.push_back(dest);
  498. mMaterials.push_back(src.mMaterial);
  499. }
  500. else
  501. {
  502. dest = mGeometries.back();
  503. dest->setDrawRange(TRIANGLE_LIST, dest->getIndexStart(), dest->getIndexCount() + src.mIndexCount,
  504. dest->getVertexStart(), dest->getVertexCount() + src.mVertexCount);
  505. }
  506. memcpy(&vertexData[vertexCount * src.mVertexSize], &src.mVertexData[0], src.mVertexCount * src.mVertexSize);
  507. if (src.mIndexSize == sizeof(unsigned))
  508. {
  509. unsigned* srcIndices = (unsigned*)&src.mIndexData[0];
  510. if (indexSize == sizeof(unsigned))
  511. {
  512. unsigned* destIndices = (unsigned*)&indexData[indexCount * indexSize];
  513. for (unsigned j = 0; j < src.mIndexCount; ++j)
  514. {
  515. *destIndices = *srcIndices + vertexCount;
  516. ++srcIndices;
  517. ++destIndices;
  518. }
  519. }
  520. else
  521. {
  522. unsigned short* destIndices = (unsigned short*)&indexData[indexCount * indexSize];
  523. for (unsigned j = 0; j < src.mIndexCount; ++j)
  524. {
  525. *destIndices = *srcIndices + vertexCount;
  526. ++srcIndices;
  527. ++destIndices;
  528. }
  529. }
  530. }
  531. else
  532. {
  533. unsigned short* srcIndices = (unsigned short*)&src.mIndexData[0];
  534. if (indexSize == sizeof(unsigned))
  535. {
  536. unsigned* destIndices = (unsigned*)&indexData[indexCount * indexSize];
  537. for (unsigned j = 0; j < src.mIndexCount; ++j)
  538. {
  539. *destIndices = *srcIndices + vertexCount;
  540. ++srcIndices;
  541. ++destIndices;
  542. }
  543. }
  544. else
  545. {
  546. unsigned short* destIndices = (unsigned short*)&indexData[indexCount * indexSize];
  547. for (unsigned j = 0; j < src.mIndexCount; ++j)
  548. {
  549. *destIndices = *srcIndices + vertexCount;
  550. ++srcIndices;
  551. ++destIndices;
  552. }
  553. }
  554. }
  555. vertexCount += src.mVertexCount;
  556. indexCount += src.mIndexCount;
  557. }
  558. mVertexBuffer->unlock();
  559. mIndexBuffer->unlock();
  560. mGeometriesDirty = false;
  561. }