CustomObject.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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::processRayQuery(RayOctreeQuery& query, float initialDistance)
  181. {
  182. PROFILE(CustomObject_Raycast);
  183. RayQueryLevel level = query.mLevel;
  184. const Matrix4x3& worldTransform = getWorldTransform();
  185. float nearest = M_INFINITY;
  186. unsigned nearestGeometry = 0;
  187. switch (level)
  188. {
  189. case RAY_AABB_NOSUBOBJECTS:
  190. {
  191. RayQueryResult result;
  192. result.mNode = this;
  193. result.mDistance = initialDistance;
  194. query.mResult.push_back(result);
  195. return;
  196. }
  197. case RAY_AABB:
  198. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  199. {
  200. const CustomGeometry& geom = mCustomGeometries[i];
  201. BoundingBox geometryBox = geom.mBoundingBox.getTransformed(worldTransform);
  202. float distance = geometryBox.getDistance(query.mRay);
  203. if ((distance < query.mMaxDistance) && (distance < nearest))
  204. {
  205. nearest = distance;
  206. nearestGeometry = i;
  207. }
  208. }
  209. break;
  210. case RAY_OBB:
  211. {
  212. Matrix4x3 inverse = worldTransform.getInverse();
  213. Ray localRay(inverse * query.mRay.mOrigin, inverse * Vector4(query.mRay.mDirection, 0.0f));
  214. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  215. {
  216. const CustomGeometry& geom = mCustomGeometries[i];
  217. float distance = geom.mBoundingBox.getDistance(localRay);
  218. if ((distance < query.mMaxDistance) && (distance < nearest))
  219. {
  220. nearest = distance;
  221. nearestGeometry = i;
  222. }
  223. }
  224. }
  225. break;
  226. case RAY_TRIANGLE:
  227. {
  228. Matrix4x3 inverse = worldTransform.getInverse();
  229. Ray localRay(inverse * query.mRay.mOrigin, inverse * Vector4(query.mRay.mDirection, 0.0f));
  230. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  231. {
  232. // Do an initial OBB test
  233. const CustomGeometry& geom = mCustomGeometries[i];
  234. float distance = geom.mBoundingBox.getDistance(localRay);
  235. if ((distance < query.mMaxDistance) && (distance < nearest))
  236. {
  237. // Then a triangle-level test
  238. distance = geom.getDistance(localRay);
  239. if ((distance < query.mMaxDistance) && (distance < nearest))
  240. {
  241. nearest = distance;
  242. nearestGeometry = i;
  243. }
  244. }
  245. }
  246. }
  247. break;
  248. }
  249. // Return the nearest hit against a geometry
  250. if (nearest < M_INFINITY)
  251. {
  252. RayQueryResult result;
  253. result.mNode = this;
  254. result.mDistance = nearest;
  255. result.mSubObject = nearestGeometry;
  256. query.mResult.push_back(result);
  257. }
  258. }
  259. void CustomObject::updateGeometry(const FrameInfo& frame, Renderer* renderer)
  260. {
  261. if (mGeometriesDirty)
  262. updateBuffer(renderer);
  263. }
  264. unsigned CustomObject::getNumBatches()
  265. {
  266. return mGeometries.size();
  267. }
  268. Geometry* CustomObject::getBatchGeometry(unsigned batchIndex)
  269. {
  270. return mGeometries[batchIndex];
  271. }
  272. Material* CustomObject::getBatchMaterial(unsigned batchIndex)
  273. {
  274. return mMaterials[batchIndex];
  275. }
  276. bool CustomObject::drawOcclusion(OcclusionBuffer* buffer)
  277. {
  278. bool success = true;
  279. for (unsigned i = 0; i < mGeometries.size(); ++i)
  280. {
  281. Geometry* geom = mGeometries[i];
  282. if (!geom)
  283. continue;
  284. // Check that the material is suitable for occlusion (default material always is)
  285. // and set culling mode
  286. Material* mat = mMaterials[i];
  287. if (mat)
  288. {
  289. if (!mat->getOcclusion())
  290. continue;
  291. buffer->setCullMode(mat->getOcclusionCullMode());
  292. }
  293. else
  294. buffer->setCullMode(CULL_CCW);
  295. const unsigned char* vertexData;
  296. unsigned vertexSize;
  297. const unsigned char* indexData;
  298. unsigned indexSize;
  299. geom->lockRawData(vertexData, vertexSize, indexData, indexSize);
  300. // Check for valid geometry data
  301. if ((!vertexData) || (!indexData))
  302. continue;
  303. unsigned indexStart = geom->getIndexStart();
  304. unsigned indexCount = geom->getIndexCount();
  305. // Draw and check for running out of triangles
  306. if (!buffer->draw(getWorldTransform(), vertexData, vertexSize, indexData, indexSize, indexStart, indexCount))
  307. success = false;
  308. geom->unlockRawData();
  309. if (!success)
  310. break;
  311. }
  312. return success;
  313. }
  314. bool CustomObject::setVertexElementMask(unsigned mask)
  315. {
  316. if (!(mask & MASK_POSITION))
  317. {
  318. LOGERROR("Custom object vertex data must contain positions");
  319. return false;
  320. }
  321. if (mask == mVertexElementMask)
  322. return true;
  323. mVertexElementMask = mask;
  324. // If geometries exist, clear their contents, but retain the amount
  325. unsigned numGeometries = mCustomGeometries.size();
  326. if (numGeometries)
  327. {
  328. mCustomGeometries.clear();
  329. mCustomGeometries.resize(numGeometries);
  330. mGeometriesDirty = true;
  331. }
  332. return true;
  333. }
  334. void CustomObject::setNumGeometries(unsigned num)
  335. {
  336. if (num != mCustomGeometries.size())
  337. {
  338. mCustomGeometries.resize(num);
  339. mGeometriesDirty = true;
  340. }
  341. }
  342. bool CustomObject::setGeometryData(unsigned index, const void* vertexData, unsigned vertexCount, const void* indexData, unsigned indexCount, bool largeIndices)
  343. {
  344. if (index >= mCustomGeometries.size())
  345. {
  346. LOGERROR("Illegal geometry index");
  347. return false;
  348. }
  349. CustomGeometry& geom = mCustomGeometries[index];
  350. geom.mVertexSize = VertexBuffer::getVertexSize(mVertexElementMask);
  351. if (vertexCount)
  352. {
  353. geom.mVertexData = new unsigned char[vertexCount * mVertexElementMask];
  354. geom.mVertexCount = vertexCount;
  355. memcpy(&geom.mVertexData[0], vertexData, vertexCount * geom.mVertexSize);
  356. geom.mBoundingBox.mDefined = false;
  357. for (unsigned i = 0; i < vertexCount; ++i)
  358. {
  359. Vector3 point((float*)&geom.mVertexData[i * geom.mVertexSize]);
  360. geom.mBoundingBox.merge(point);
  361. }
  362. }
  363. else
  364. {
  365. geom.mVertexData.reset();
  366. geom.mVertexCount = 0;
  367. }
  368. geom.mIndexSize = largeIndices ? sizeof(unsigned) : sizeof(unsigned short);
  369. geom.mIndexCount = indexCount;
  370. if (indexCount)
  371. {
  372. geom.mIndexData = new unsigned char[geom.mIndexCount * geom.mIndexSize];
  373. memcpy(&geom.mIndexData[0], indexData, geom.mIndexCount * geom.mIndexSize);
  374. }
  375. else
  376. geom.mIndexData.reset();
  377. calculateBoundingBox();
  378. mGeometriesDirty = true;
  379. return true;
  380. }
  381. void CustomObject::setMaterial(Material* material)
  382. {
  383. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  384. setMaterial(i, material);
  385. }
  386. bool CustomObject::setMaterial(unsigned index, Material* material)
  387. {
  388. if (index >= mCustomGeometries.size())
  389. {
  390. LOGERROR("Illegal material index");
  391. return false;
  392. }
  393. mCustomGeometries[index].mMaterial = material;
  394. if ((!mOptimization) && (!mGeometriesDirty) && (mMaterials.size() == mCustomGeometries.size()))
  395. mMaterials[index] = material;
  396. else
  397. mGeometriesDirty = true;
  398. return true;
  399. }
  400. void CustomObject::setOptimization(bool enable)
  401. {
  402. if (enable != mOptimization)
  403. {
  404. mOptimization = enable;
  405. mGeometriesDirty = true;
  406. }
  407. }
  408. const CustomGeometry* CustomObject::getGeometry(unsigned index) const
  409. {
  410. if (index >= mCustomGeometries.size())
  411. return 0;
  412. return &mCustomGeometries[index];
  413. }
  414. Material* CustomObject::getMaterial(unsigned index) const
  415. {
  416. if (index >= mCustomGeometries.size())
  417. return 0;
  418. return mCustomGeometries[index].mMaterial;
  419. }
  420. void CustomObject::onWorldBoundingBoxUpdate(BoundingBox& worldBoundingBox)
  421. {
  422. worldBoundingBox = mBoundingBox.getTransformed(getWorldTransform());
  423. }
  424. void CustomObject::calculateBoundingBox()
  425. {
  426. mBoundingBox.mMin = Vector3::sZero;
  427. mBoundingBox.mMax = Vector3::sZero;
  428. mBoundingBox.mDefined = false;
  429. for (unsigned i = 0; i < mCustomGeometries.size(); ++i)
  430. {
  431. const CustomGeometry& geom = mCustomGeometries[i];
  432. if ((geom.mVertexCount) && (geom.mIndexCount))
  433. mBoundingBox.merge(geom.mBoundingBox);
  434. }
  435. VolumeNode::onMarkedDirty();
  436. }
  437. void CustomObject::updateBuffer(Renderer* renderer)
  438. {
  439. PROFILE(CustomObject_UpdateBuffer);
  440. if (!mVertexBuffer)
  441. mVertexBuffer = new VertexBuffer(renderer);
  442. if (!mIndexBuffer)
  443. mIndexBuffer = new IndexBuffer(renderer);
  444. unsigned totalVertexCount = 0;
  445. unsigned totalIndexCount = 0;
  446. mGeometries.clear();
  447. mMaterials.clear();
  448. std::vector<CustomGeometry>* customGeometries;
  449. static std::vector<CustomGeometry> sortedGeometries;
  450. if (mOptimization)
  451. {
  452. // For optimization to work, sort batches per material first
  453. sortedGeometries.resize(mCustomGeometries.size());
  454. sortedGeometries = mCustomGeometries;
  455. std::sort(sortedGeometries.begin(), sortedGeometries.end(), compareCustomGeometries);
  456. customGeometries = &sortedGeometries;
  457. }
  458. else
  459. customGeometries = &mCustomGeometries;
  460. for (unsigned i = 0; i < customGeometries->size(); ++i)
  461. {
  462. const CustomGeometry& src = (*customGeometries)[i];
  463. if ((!src.mVertexCount) || (!src.mIndexCount))
  464. continue;
  465. totalVertexCount += src.mVertexCount;
  466. totalIndexCount += src.mIndexCount;
  467. }
  468. // Use 16-bit indices if possible
  469. unsigned indexSize = totalVertexCount >= 65536 ? sizeof(unsigned) : sizeof(short);
  470. unsigned vertexCount = 0;
  471. unsigned indexCount = 0;
  472. mVertexBuffer->setSize(totalVertexCount, mVertexElementMask);
  473. mIndexBuffer->setSize(totalIndexCount, indexSize);
  474. unsigned char* vertexData = (unsigned char*)mVertexBuffer->lock(0, totalVertexCount, LOCK_NORMAL);
  475. unsigned char* indexData = (unsigned char*)mIndexBuffer->lock(0, totalIndexCount, LOCK_NORMAL);
  476. for (unsigned i = 0; i < customGeometries->size(); ++i)
  477. {
  478. const CustomGeometry& src = (*customGeometries)[i];
  479. if ((!src.mVertexCount) || (!src.mIndexCount))
  480. continue;
  481. SharedPtr<Geometry> dest;
  482. // If not optimized, build a new geometry for each batch
  483. // Otherwise check if the material is same, and expand the draw range in that case
  484. bool newGeometry = true;
  485. if ((mOptimization) && (mGeometries.size()) && (mMaterials.back() == src.mMaterial))
  486. newGeometry = false;
  487. if (newGeometry)
  488. {
  489. dest = new Geometry();
  490. dest->setIndexBuffer(mIndexBuffer);
  491. dest->setVertexBuffer(0, mVertexBuffer);
  492. dest->setDrawRange(TRIANGLE_LIST, indexCount, src.mIndexCount, vertexCount, src.mVertexCount);
  493. mGeometries.push_back(dest);
  494. mMaterials.push_back(src.mMaterial);
  495. }
  496. else
  497. {
  498. dest = mGeometries.back();
  499. dest->setDrawRange(TRIANGLE_LIST, dest->getIndexStart(), dest->getIndexCount() + src.mIndexCount,
  500. dest->getVertexStart(), dest->getVertexCount() + src.mVertexCount);
  501. }
  502. memcpy(&vertexData[vertexCount * src.mVertexSize], &src.mVertexData[0], src.mVertexCount * src.mVertexSize);
  503. if (src.mIndexSize == sizeof(unsigned))
  504. {
  505. unsigned* srcIndices = (unsigned*)&src.mIndexData[0];
  506. if (indexSize == sizeof(unsigned))
  507. {
  508. unsigned* destIndices = (unsigned*)&indexData[indexCount * indexSize];
  509. for (unsigned j = 0; j < src.mIndexCount; ++j)
  510. {
  511. *destIndices = *srcIndices + vertexCount;
  512. ++srcIndices;
  513. ++destIndices;
  514. }
  515. }
  516. else
  517. {
  518. unsigned short* destIndices = (unsigned short*)&indexData[indexCount * indexSize];
  519. for (unsigned j = 0; j < src.mIndexCount; ++j)
  520. {
  521. *destIndices = *srcIndices + vertexCount;
  522. ++srcIndices;
  523. ++destIndices;
  524. }
  525. }
  526. }
  527. else
  528. {
  529. unsigned short* srcIndices = (unsigned short*)&src.mIndexData[0];
  530. if (indexSize == sizeof(unsigned))
  531. {
  532. unsigned* destIndices = (unsigned*)&indexData[indexCount * indexSize];
  533. for (unsigned j = 0; j < src.mIndexCount; ++j)
  534. {
  535. *destIndices = *srcIndices + vertexCount;
  536. ++srcIndices;
  537. ++destIndices;
  538. }
  539. }
  540. else
  541. {
  542. unsigned short* destIndices = (unsigned short*)&indexData[indexCount * indexSize];
  543. for (unsigned j = 0; j < src.mIndexCount; ++j)
  544. {
  545. *destIndices = *srcIndices + vertexCount;
  546. ++srcIndices;
  547. ++destIndices;
  548. }
  549. }
  550. }
  551. vertexCount += src.mVertexCount;
  552. indexCount += src.mIndexCount;
  553. }
  554. mVertexBuffer->unlock();
  555. mIndexBuffer->unlock();
  556. mGeometriesDirty = false;
  557. }