SO3Engine
ALMesh.cpp
Go to the documentation of this file.
1
5#include <OgreHardwareBuffer.h>
6#include <OgreMesh.h>
7#include <OgreSubMesh.h>
8#include <OgreLog.h>
9#include <OgreLogManager.h>
10
11#include "OgreMeshLodGenerator.h"
12#include "OgrePixelCountLodStrategy.h"
13#include "OgreLodData.h"
14#include "OgreLodConfig.h"
15#include "OgreLodCollapser.h"
16
18#include "SO3Renderer/SO3Root.h"
19
20namespace SO3
21{
22 ALMesh::ALMesh(aiNode* meNode, ALScene* alscene)
23 {
24 mOrigin = meNode;
25 mScene = alscene;
26 mHasBone = false;
27 mSkeleton.reset();
28 mOgreMesh.reset();
29 mBounding.setNull();
30 }
31
33 {
34 //delete resource
35 if (mOgreMesh)
36 {
37 Ogre::MeshManager::getSingleton().remove(mOgreMesh->getHandle());
38
39 // force resource destruction
40 while (mOgreMesh)
41 mOgreMesh.reset();
42 }
43 }
44
45 void ALMesh::updateBounds(Ogre::Vector3 pos)
46 {
47 Ogre::Vector3 minB = mBounding.getMinimum();
48 Ogre::Vector3 maxB = mBounding.getMaximum();
49 minB.x = std::min(minB.x, pos.x);
50 minB.y = std::min(minB.y, pos.y);
51 minB.z = std::min(minB.z, pos.z);
52 maxB.x = std::max(maxB.x, pos.x);
53 maxB.y = std::max(maxB.y, pos.y);
54 maxB.z = std::max(maxB.z, pos.z);
55 mBounding.setMinimum(minB);
56 mBounding.setMaximum(maxB);
57
58 mSphereRadius = std::max(mSphereRadius, pos.length());
59 }
60
61 Ogre::MeshPtr ALMesh::generateMesh()
62 {
63 std::string meshName = std::string(mOrigin->mName.C_Str());
64
65 //For complex ifc node names we remove the hash
66 if (meshName.find("Ifc") != std::string::npos)
67 meshName = meshName.substr(0, meshName.length() - 22);
68
69 if (meshName == "")
70 meshName = ALStringCleaner::cleanString(mScene->getSceneName());
71 else
72 meshName = ALStringCleaner::cleanString(meshName);
73
74 // Build the main Mesh.
75 try
76 {
77 mOgreMesh = Ogre::MeshManager::getSingleton().createManual(meshName.c_str(), mScene->getRessourceGroup());
78 }
79 catch(Ogre::Exception &)
80 {
81 // Mesh name duplicated or group ressource error
82 return mOgreMesh;
83 }
84
85 //check if bones are present
86 unsigned int nbSubMeshes = mOrigin->mNumMeshes;
87 for(unsigned int n=0; n < mOrigin->mNumMeshes; ++n)
88 {
89 aiMesh* subMesh = mScene->getAiScene()->mMeshes[mOrigin->mMeshes[n]];
90
91 if (subMesh->HasBones())
92 {
93 mHasBone = true;
94 break;
95 }
96 }
97
98 if (mHasBone)
99 {
100 std::string skeletonName = mOgreMesh->getName() + ".skeleton";
101 mSkeleton = Ogre::SkeletonManager::getSingleton().create(skeletonName, mScene->getRessourceGroup(), true);
102 ALSkeleton sklAnim(mScene, mSkeleton, mOrigin);
103 mSkeletonAnim = sklAnim;
104 }
105
106 //TODO if computer compatible or flag generate shared vertices buffer
107 generateSubMesh(mOgreMesh);
108
109 //disable log warning
110 bool lastLogstate = SRoot::getSingletonPtr()->GetLogEnable();
112
113 if (mHasBone)
114 {
115 aiMatrix4x4 meshInverseTrans = (mOrigin->mParent != NULL) ? mOrigin->mParent->mTransformation * mOrigin->mTransformation : mOrigin->mTransformation;
116 meshInverseTrans.Inverse();
117 mSkeletonAnim.makeHierarchy(meshInverseTrans);
118 mSkeletonAnim.processAnimation();
119 try
120 {
121 mOgreMesh->setSkeletonName(mOgreMesh->getName() + ".skeleton");
122 }
123 catch(Ogre::Exception &)
124 {
125 //ignore loading exception
126 }
127 }
128
129 // The bounding box of the mesh :
130 Ogre::AxisAlignedBox bbox = mOgreMesh->getBounds();
131 Ogre::Vector3 min1 = mBounding.getMinimum();
132 Ogre::Vector3 max1 = mBounding.getMaximum();
133
134 //reverse Z need it ?
135 Ogre::Vector3 min2(min1.x, min1.y, min1.z);
136 Ogre::Vector3 max2(max1.x, max1.y, max1.z);
137 Ogre::AxisAlignedBox newbbox;
138 newbbox.setExtents(min2, max2);
139 bbox.merge(newbbox);
140
141 // Set Tangeant
142 bool canBuild;
143 unsigned short srcTex, destTex;
144 Ogre::VertexElementSemantic targetSemantic = Ogre::VES_TANGENT;
145 try
146 {
147 canBuild = !mOgreMesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, srcTex, destTex);
148
149 if (canBuild)
150 mOgreMesh->buildTangentVectors(targetSemantic, srcTex, destTex, false, false, false);
151 }
152 catch (Ogre::Exception &)
153 {
154 canBuild = false;
155 }
156
157 // enable logs again
158 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
159
160 // Define mesh bounds
161 mOgreMesh->_setBounds(bbox, false);
162 mOgreMesh->_setBoundingSphereRadius(mSphereRadius);
163
164 // Optimize the mesh buffers
165 if (mOgreMesh->sharedVertexData)
166 {
167 Ogre::VertexData* vdata = mOgreMesh->getVertexDataByTrackHandle(0);
168 Ogre::VertexDeclaration* newadcl = vdata->vertexDeclaration->getAutoOrganisedDeclaration(mOgreMesh->hasSkeleton(), mOgreMesh->hasVertexAnimation(), mOgreMesh->getSharedVertexDataAnimationIncludesNormals());
169 vdata->reorganiseBuffers(newadcl);
170 vdata->removeUnusedBuffers();
171
172 // Automatic
173 Ogre::VertexDeclaration* newDcl = mOgreMesh->sharedVertexData->vertexDeclaration->getAutoOrganisedDeclaration(
174 mOgreMesh->hasSkeleton(), mOgreMesh->hasVertexAnimation(), mOgreMesh->getSharedVertexDataAnimationIncludesNormals());
175
176 vdata->reorganiseBuffers(newDcl);
177
178 mOgreMesh->sharedVertexData->removeUnusedBuffers();
179 }
180
181 const Ogre::Mesh::SubMeshList submeshes = mOgreMesh->getSubMeshes();
182 int subIdx = 0;
183 for (unsigned int i = 0; i < submeshes.size(); i++)
184 {
185 Ogre::SubMesh* sm = submeshes[i];
186 if (!sm->useSharedVertices)
187 {
188 const bool hasVertexAnim = sm->getVertexAnimationType() != Ogre::VAT_NONE;
189
190 Ogre::VertexData* vdata = mOgreMesh->getVertexDataByTrackHandle(subIdx + 1);
191 Ogre::VertexDeclaration* newadcl = vdata->vertexDeclaration->getAutoOrganisedDeclaration(mOgreMesh->hasSkeleton(), hasVertexAnim, sm->getVertexAnimationIncludesNormals());
192 vdata->reorganiseBuffers(newadcl);
193 vdata->removeUnusedBuffers();
194
195 // Automatic
196 Ogre::VertexDeclaration* newDcl = sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(
197 mOgreMesh->hasSkeleton(), hasVertexAnim, sm->getVertexAnimationIncludesNormals());
198
199 if (*newDcl != *(sm->vertexData->vertexDeclaration))
200 sm->vertexData->reorganiseBuffers(newDcl);
201
202 sm->vertexData->removeUnusedBuffers();
203 }
204 subIdx++;
205 }
206
207 return mOgreMesh;
208 }
209
210 void ALMesh::generateSubMesh(Ogre::MeshPtr ogMesh)
211 {
212 // Build all the submeshes.
213 const std::vector<std::string> materialNames = mScene->getMaterialNames();
214 unsigned int nbSubMeshes = mOrigin->mNumMeshes;
215 Ogre::MaterialManager* materialManager = Ogre::MaterialManager::getSingletonPtr();
216 std::string matName;
217
218 for(unsigned int n=0; n<nbSubMeshes; ++n)
219 {
220 aiMesh* currentSubMesh = mScene->getAiScene()->mMeshes[mOrigin->mMeshes[n]];
221 std::string smName = currentSubMesh->mName.C_Str();
222 smName = ALStringCleaner::cleanString(smName);
223
224 Ogre::SubMesh* submesh = ogMesh->createSubMesh(smName);
225 submesh->operationType = (currentSubMesh->HasFaces()) ? Ogre::RenderOperation::OT_TRIANGLE_LIST : Ogre::RenderOperation::OT_POINT_LIST;
226
227 // TODO
228 submesh->useSharedVertices = false;
229
230 matName = materialNames[currentSubMesh->mMaterialIndex];
231 //Material need to be created in group to make setMaterialName working in last version of Ogre
232 if (!matName.empty())
233 {
234 if (!materialManager->getByName(matName, mScene->getRessourceGroup()))
235 materialManager->create(matName, mScene->getRessourceGroup());
236 submesh->setMaterialName(matName);
237 }
238
239 //adjust vertices with bones bind pose
240 //TODO remove when aiSkeleton is available
241 if (currentSubMesh->mNumBones > 0)
242 {
243 aiMatrix4x4 meshInverseTrans = mScene->getFullTransform(mOrigin);
244 meshInverseTrans.Inverse();
245 std::vector<aiVector3D> vertices(currentSubMesh->mNumVertices);
246 std::vector<aiVector3D> normals(currentSubMesh->mNumVertices);
247
248 //copy vextices pos
249 for (unsigned int i=0; i<currentSubMesh->mNumVertices; ++i)
250 {
251 vertices[i] = currentSubMesh->mVertices[i];
252 normals[i] = currentSubMesh->mNormals[i];
253 currentSubMesh->mVertices[i] = aiVector3D(0, 0, 0);
254 currentSubMesh->mNormals[i] = aiVector3D(0, 0, 0);
255 }
256
257 for(unsigned int j=0; j<currentSubMesh->mNumBones; ++j)
258 {
259 aiBone* bone = currentSubMesh->mBones[j];
260 aiNode* bnode = mScene->getAiScene()->mRootNode->FindNode(bone->mName);
261
262 if (bnode)
263 {
264 for(unsigned int w=0; w<bone->mNumWeights; ++w)
265 {
266 aiVertexWeight aiWeight = bone->mWeights[w];
267 aiMatrix4x4 boneMat = meshInverseTrans * mScene->getFullTransform(bnode) * bone->mOffsetMatrix;
268 aiMatrix3x3 normMat = aiMatrix3x3(boneMat);
269 aiVector3D vertPos = vertices[aiWeight.mVertexId];
270 aiVector3D normal = normals[aiWeight.mVertexId];
271 currentSubMesh->mVertices[aiWeight.mVertexId] += boneMat * vertPos * aiWeight.mWeight;
272 currentSubMesh->mNormals[aiWeight.mVertexId] += normMat * normal * aiWeight.mWeight;
273 }
274 }
275 }
276
277 vertices.clear();
278 normals.clear();
279 }
280
281 makeIndexBuffer(currentSubMesh, submesh);
282 makeVertexBuffer(currentSubMesh, submesh);
283
284 if (currentSubMesh->mNumBones > 0)
285 {
286 for(unsigned int n=0; n<currentSubMesh->mNumBones; ++n)
287 {
288 aiNode* bnode = mScene->getAiScene()->mRootNode->FindNode(currentSubMesh->mBones[n]->mName);
289 aiNode* newBone = 0;
290 aiNode* curBone = bnode;
291 while(curBone && (curBone->mNumMeshes == 0) && (curBone != mScene->getAiScene()->mRootNode))
292 {
293 newBone = curBone;
294 curBone = curBone->mParent;
295 }
296
297 if (newBone)
298 {
299 //add current
300 mSkeletonAnim.addBone(newBone, 0, submesh);
301
302 // add all sons
303 std::queue<aiNode*> nodes;
304 nodes.push(newBone);
305 while(!nodes.empty())
306 {
307 newBone = nodes.front();
308 nodes.pop();
309
310 // Get the number of son.
311 unsigned int nbSons = newBone->mNumChildren;
312
313 // while there is still sons, we go through each of them add
314 // add them to the queue.
315 if(nbSons>0)
316 {
317 aiNode** sons = newBone->mChildren;
318
319 for(unsigned int n=0; n<nbSons; ++n)
320 {
321 // We get the son 1 by 1.
322 aiNode* son = sons[n];
323 if (son && mScene->isBone(son) && (son->mNumMeshes == 0) && (son != mScene->getAiScene()->mRootNode))
324 {
325 mSkeletonAnim.addBone(son, 0, submesh);
326 nodes.push(son);
327 }
328 }
329 }
330 }
331 }
332
333 // add the bone with mesh weights
334 if (bnode)
335 mSkeletonAnim.addBone(bnode, currentSubMesh->mBones[n], submesh);
336 }
337 }
338 ogMesh->_updateCompiledBoneAssignments();
339
340 //optim memory for very big object when the scene only have one mesh (otherwise it can be used in instances nodes)
341 if (/*(!mScene->IsLoaderModeEnable()) &&*/ (mScene->getAiScene()->mNumMeshes == 1) && (mScene->getAiScene()->mRootNode->mNumChildren == 0))
342 {
343 aiScene* curScene = const_cast<aiScene*>(mScene->getAiScene());
344 delete currentSubMesh;
345 curScene->mMeshes[mOrigin->mMeshes[n]] = 0;
346 curScene->mNumMeshes -= 1;
347 }
348 }
349 }
350
351 void ALMesh::makeIndexBuffer(aiMesh* asSubMesh, Ogre::SubMesh* ogSubMesh)
352 {
353 ogSubMesh->vertexData = new Ogre::VertexData();
354 ogSubMesh->vertexData->vertexStart = 0;
355 ogSubMesh->vertexData->vertexCount = asSubMesh->mNumVertices;
356
357 if (asSubMesh->mNumFaces > 0)
358 {
359 bool bUse32BitIndexes = (asSubMesh->mNumVertices > 65535) ? true : false;
360
361 // Create a new index buffer
362 ogSubMesh->indexData->indexStart = 0;
363 ogSubMesh->indexData->indexCount = asSubMesh->mNumFaces * 3;
364
365 ogSubMesh->indexData->indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
366 bUse32BitIndexes ? Ogre::HardwareIndexBuffer::IT_32BIT : Ogre::HardwareIndexBuffer::IT_16BIT,
367 ogSubMesh->indexData->indexCount,
368 Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
369
370 std::vector<std::vector<int>> facesIndex;
371 facesIndex.resize(asSubMesh->mNumFaces);
372
373 // rebuild vertices index, it must start on 0
374 for (unsigned int i = 0; i < asSubMesh->mNumFaces; i++)
375 {
376 facesIndex[i].resize(3);
377 for (size_t j = 0; j < 3; j++)
378 {
379 if (asSubMesh->mFaces[i].mIndices[j] >= asSubMesh->mNumVertices)
380 facesIndex[i][j] = 0;
381 else
382 facesIndex[i][j] = asSubMesh->mFaces[i].mIndices[j];
383 }
384 }
385 //delete [] asSubMesh->mFaces;
386 //asSubMesh->mFaces = NULL;
387 //asSubMesh->mNumFaces = 0;
388
389 // Fill the index buffer with faces data
390 if (bUse32BitIndexes)
391 {
392 Ogre::uint32* pIdx = static_cast<Ogre::uint32*>(ogSubMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
393 for (unsigned int i = 0; i < facesIndex.size(); i++)
394 {
395 *pIdx++ = static_cast<Ogre::uint32>(facesIndex[i][0]);
396 *pIdx++ = static_cast<Ogre::uint32>(facesIndex[i][1]);
397 *pIdx++ = static_cast<Ogre::uint32>(facesIndex[i][2]);
398 }
399 ogSubMesh->indexData->indexBuffer->unlock();
400 }
401 else
402 {
403 Ogre::uint16* pIdx = static_cast<Ogre::uint16*>(ogSubMesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
404 for (unsigned int i = 0; i < facesIndex.size(); i++)
405 {
406 *pIdx++ = static_cast<Ogre::uint16>(facesIndex[i][0]);
407 *pIdx++ = static_cast<Ogre::uint16>(facesIndex[i][1]);
408 *pIdx++ = static_cast<Ogre::uint16>(facesIndex[i][2]);
409 }
410 ogSubMesh->indexData->indexBuffer->unlock();
411 }
412 facesIndex.clear();
413 }
414 }
415
416 void ALMesh::makeVertexBuffer(aiMesh* asSubMesh, Ogre::SubMesh* ogSubMesh)
417 {
418 // The arrays that contain the mesh data.
419 aiVector3D* vertices = asSubMesh->mVertices;
420 aiVector3D* normals = asSubMesh->mNormals;
421 aiVector3D* tangents = asSubMesh->mTangents;
422 aiVector3D* bitangent = asSubMesh->mBitangents;
423
424 // For the time being, we only take the first texture coords of the mesh.
425 std::vector<aiVector3D*> uv;
426 unsigned int nbUV = asSubMesh->GetNumUVChannels();
427 for(unsigned int n=0; n<nbUV; ++n)
428 {
429 uv.push_back(asSubMesh->mTextureCoords[n]);
430 }
431
432 std::vector<aiColor4D*> color;
433 unsigned int nbCol = asSubMesh->GetNumColorChannels();
434 for(unsigned int n=0; n<nbCol; ++n)
435 {
436 color.push_back(asSubMesh->mColors[n]);
437 }
438
439 // We prepare Ogre before feeding the datas.
440 Ogre::VertexDeclaration* declaration = ogSubMesh->vertexData->vertexDeclaration;
441 Ogre::VertexBufferBinding* bind = ogSubMesh->vertexData->vertexBufferBinding;
442
443 size_t vBufSegmentSize = 0;
444 size_t texSegmentSize = 0;
445
446 declaration->addElement(0, vBufSegmentSize, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
447 vBufSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
448
449 // Set up the offset.
450 if(normals)
451 {
452 declaration->addElement(0, vBufSegmentSize, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
453 vBufSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
454 }
455
456 if (tangents)
457 {
458 declaration->addElement(0, vBufSegmentSize, Ogre::VET_FLOAT3, Ogre::VES_TANGENT);
459 vBufSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
460 }
461
462 if (bitangent)
463 {
464 declaration->addElement(0, vBufSegmentSize, Ogre::VET_FLOAT3, Ogre::VES_BINORMAL);
465 vBufSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
466 }
467
468 for(unsigned int n=0; n<color.size(); ++n)
469 {
470 declaration->addElement(0, vBufSegmentSize, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
471 vBufSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
472 }
473
474 int countTex = 0;
475 if (nbUV == 0)
476 {
477 declaration->addElement(1, texSegmentSize, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, countTex);
478 texSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
479 countTex++;
480 }
481 else
482 {
483 for (unsigned int n = 0; n < uv.size(); ++n)
484 {
485 declaration->addElement(1, texSegmentSize, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, countTex);
486 texSegmentSize += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
487 countTex++;
488 }
489 }
490
491 // Now create the vertex buffers.
492 Ogre::HardwareVertexBufferSharedPtr vbuffer = Ogre::HardwareBufferManager::getSingletonPtr()
493 ->createVertexBuffer(vBufSegmentSize, ogSubMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
494
495 //add UV buffer even if there are none for D3D shaders.
496 Ogre::HardwareVertexBufferSharedPtr texBuf = Ogre::HardwareBufferManager::getSingletonPtr()
497 ->createVertexBuffer(texSegmentSize, ogSubMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
498
499 // Bind them.
500 bind->setBinding(0, vbuffer);
501 bind->setBinding(1, texBuf);
502
503 // Lock them. pVert & pTexVert are pointers to the start of the hardware buffers.
504 unsigned char* pVert = static_cast<unsigned char*>(vbuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
505 unsigned char* pTexVert = static_cast<unsigned char*>(texBuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
506
507 Ogre::ARGB* pCol;
508 float* pFloat;
509
510 // Get the element lists for the buffers.
511 Ogre::VertexDeclaration::VertexElementList elems = declaration->findElementsBySource(0);
512 Ogre::VertexDeclaration::VertexElementList texElems = declaration->findElementsBySource(1);
513
514 // Buffers are set up, so iterate the vertices.
515 int iTexCoord = 0;
516 for (unsigned int i = 0; i < asSubMesh->mNumVertices; ++i)
517 {
518 Ogre::VertexDeclaration::VertexElementList::const_iterator elemItr, elemEnd;
519 elemEnd = elems.end();
520 for (elemItr = elems.begin(); elemItr != elemEnd; ++elemItr)
521 {
522 // VertexElement corresponds to a part of a vertex definition eg. position, normal
523 const Ogre::VertexElement& elem = *elemItr;
524 switch (elem.getSemantic())
525 {
526 case Ogre::VES_POSITION:
527 {
528 elem.baseVertexPointerToElement(pVert, &pFloat);
529
530 if (mBounding.isNull())
531 mBounding = Ogre::AxisAlignedBox(Ogre::Vector3(vertices[i].x, vertices[i].y, vertices[i].z), Ogre::Vector3(vertices[i].x, vertices[i].y, vertices[i].z));
532 else
533 updateBounds(Ogre::Vector3(vertices[i].x, vertices[i].y, vertices[i].z));
534 *pFloat++ = vertices[i].x;
535 *pFloat++ = vertices[i].y;
536 *pFloat++ = vertices[i].z;
537 }
538 break;
539 case Ogre::VES_NORMAL:
540 {
541 elem.baseVertexPointerToElement(pVert, &pFloat);
542 *pFloat++ = normals[i].x;
543 *pFloat++ = normals[i].y;
544 *pFloat++ = normals[i].z;
545 }
546 break;
547 case Ogre::VES_TANGENT:
548 {
549 elem.baseVertexPointerToElement(pVert, &pFloat);
550 *pFloat++ = tangents[i].x;
551 *pFloat++ = tangents[i].y;
552 *pFloat++ = tangents[i].z;
553 }
554 break;
555 case Ogre::VES_BINORMAL:
556 {
557 elem.baseVertexPointerToElement(pVert, &pFloat);
558 *pFloat++ = bitangent[i].x;
559 *pFloat++ = bitangent[i].y;
560 *pFloat++ = bitangent[i].z;
561 }
562 break;
563 case Ogre::VES_DIFFUSE:
564 {
565 elem.baseVertexPointerToElement(pVert, &pCol);
566 Ogre::ColourValue cv(color[0][i].r, color[0][i].g, color[0][i].b, color[0][i].a);
567 *pCol = Ogre::VertexElement::convertColourValue(cv, Ogre::VertexElement::getBestColourVertexElementType());
568 }
569 break;
570 default:
571 break;
572 } // Deal with an individual vertex element (position or normal).
573 } // Loop positions and normals.
574
575 iTexCoord = 0;
576 elemEnd = texElems.end();
577 for (elemItr = texElems.begin(); elemItr != elemEnd; ++elemItr)
578 {
579 // VertexElement corresponds to a part of a vertex definition eg. tex coord
580 const Ogre::VertexElement& elem = *elemItr;
581 switch (elem.getSemantic())
582 {
583 case Ogre::VES_TEXTURE_COORDINATES:
584 {
585 elem.baseVertexPointerToElement(pTexVert, &pFloat);
586 if (nbUV == 0)
587 {
588 *pFloat++ = 0.0;
589 *pFloat++ = 0.0;
590 }
591 else
592 {
593 *pFloat++ = uv[iTexCoord][i].x;
594 *pFloat++ = 1 - uv[iTexCoord][i].y;
595 }
596
597 iTexCoord++;
598 }
599 break;
600 default:
601 break;
602 } // Deal with an individual vertex element (tex coords).
603 } // Loop tex coords.
604
605 pVert += vbuffer->getVertexSize();
606 pTexVert += texBuf->getVertexSize();
607 } // Loop vertices.
608
609 vbuffer->unlock();
610 texBuf->unlock();
611
612 //cleanup memory
613 /*for (unsigned int n = 0; n<nbUV; ++n)
614 {
615 if (asSubMesh->mTextureCoords[n])
616 delete [] asSubMesh->mTextureCoords[n];
617 asSubMesh->mTextureCoords[n] = NULL;
618 }
619
620 for (unsigned int n = 0; n<nbCol; ++n)
621 {
622 if (asSubMesh->mColors[n])
623 delete[] asSubMesh->mColors[n];
624 asSubMesh->mColors[n] = NULL;
625 }
626
627 if (asSubMesh->mVertices)
628 delete[] asSubMesh->mVertices;
629 asSubMesh->mVertices = NULL;
630
631 if (asSubMesh->mNormals)
632 delete[] asSubMesh->mNormals;
633 asSubMesh->mNormals = NULL;
634
635 asSubMesh->mNumVertices = 0;
636 */
637 }
638
639 void ALMesh::saveMesh(Ogre::MeshPtr ogMesh, boost::filesystem::path path, tinyxml2::XMLElement* parent)
640 {
641 if(mHasBone)
642 {
643 Ogre::SkeletonSerializer sklSer;
644 boost::filesystem::path sklPath(path);
645 sklPath /= "meshes/";
646 std::string sklFile(sklPath.generic_string()+ogMesh->getName()+".skeleton");
647 sklSer.exportSkeleton(mSkeleton.get(), sklFile);
648 }
649
650 size_t nbsubmesh = ogMesh->getNumSubMeshes();
651 size_t numVertices = 0;
652 for (unsigned int n = 0; n<nbsubmesh; ++n)
653 {
654 Ogre::SubMesh* submesh = ogMesh->getSubMesh(n);
655 if (submesh->vertexData)
656 numVertices += submesh->vertexData->vertexCount;
657 }
658
659 tinyxml2::XMLDocument* doc = parent->GetDocument();
660 tinyxml2::XMLElement* xmlMesh = doc->NewElement("entity");
661 xmlMesh->SetAttribute("name", ogMesh->getName().c_str());
662 xmlMesh->SetAttribute("id", ALStringCleaner::curentUID().c_str());
663 std::string file = "meshes/" + ogMesh->getName()+".mesh";
664 xmlMesh->SetAttribute("meshFile", file.c_str());
665 xmlMesh->SetAttribute("castShadows", true);
666 tinyxml2::XMLElement* xmlSub = doc->NewElement("subentities");
667
668 for(unsigned int n=0; n<nbsubmesh; ++n)
669 {
670 tinyxml2::XMLElement* xmlsubmesh = doc->NewElement("subentity");
671 xmlsubmesh->SetAttribute("index", n);
672 xmlsubmesh->SetAttribute("materialName", ogMesh->getSubMesh(n)->getMaterialName().c_str());
673 xmlSub->InsertEndChild(xmlsubmesh);
674 }
675
676 xmlMesh->InsertEndChild(xmlSub);
677 parent->InsertEndChild(xmlMesh);
678
679 //Generate LOD
680 int nbLevels = 4;
681 if ((numVertices > 64) && (mScene->GetSceneLoader()->getFlags() & so3Converter_GenerateLod))
682 {
683 try //std
684 {
685 try
686 {
687 Ogre::LodConfig lodConfig;
688 lodConfig.levels.clear();
689 lodConfig.mesh = ogMesh;
690 lodConfig.strategy = Ogre::ScreenRatioPixelCountLodStrategy::getSingletonPtr();
691 lodConfig.advanced.useCompression = true;
692 lodConfig.advanced.useVertexNormals = true;
693 //lodConfig.advanced.preventPunchingHoles = true;
694 //lodConfig.advanced.preventBreakingLines = true;
695
696 int nbl = nbLevels + 2;
697 Ogre::Real reduction = 0.7f / nbLevels;
698 for (int i = 2; i < nbl; i++)
699 {
700 Ogre::Real i4 = (Ogre::Real)(i * i * i * i);
701 lodConfig.createGeneratedLodLevel(Ogre::Real(2.0) / i4, reduction * i, Ogre::LodLevel::VRM_PROPORTIONAL);
702 }
703
704 Ogre::MeshLodGenerator::getSingleton().generateLodLevels(lodConfig);
705 }
706 catch (Ogre::Exception &)
707 {
708 ogMesh->removeLodLevels();
709 MMechostr(MSKRUNTIME, "SO3Engine : failed to generate LOD levels on %s", ogMesh->getName().c_str());
710 }
711 }
712 catch (std::exception &)
713 {
714 //catch memory alloc fail
715 ogMesh->removeLodLevels();
716 MMechostr(MSKRUNTIME, "SO3Engine : failed to generate LOD levels, out of memory on %s", ogMesh->getName().c_str());
717 }
718 }
719
720 Ogre::MeshSerializer meshSer;
721 boost::filesystem::path meshPath(path);
722 meshPath /= "meshes/";
723 std::string meshFile(meshPath.generic_string() + ogMesh->getName() + ".mesh");
724 meshSer.exportMesh(ogMesh.get(), meshFile);
725
726 //delete resource
727 Ogre::MeshManager::getSingleton().remove(ogMesh->getHandle());
728
729 // force resource destruction
730 while (ogMesh)
731 ogMesh.reset();
732
733 if (mSkeleton)
734 {
735 Ogre::SkeletonManager::getSingleton().remove(mSkeleton->getHandle());
736 mSkeleton.reset();
737 }
738 }
739
740 void ALMesh::convert(boost::filesystem::path expPath, tinyxml2::XMLElement* parent)
741 {
742 Ogre::MeshPtr loadedMesh = generateMesh();
743 saveMesh(loadedMesh, expPath, parent);
744 }
745
747 {
748 Ogre::MeshPtr loadedMesh = generateMesh();
749 if (mSkeleton)
750 loadedMesh->_notifySkeleton(mSkeleton);
751
752 SEntity* scolMesh = mScene->getSScene()->CreateEntity(loadedMesh->getName(), mScene->getRessourceGroup(), loadedMesh);
753
754 return scolMesh;
755 }
756}
MMechostr(MSKDEBUG, " > Start loading Plugin SO3Engine dll\n")
SCOL_EXPORT int cbmachine w
Definition SO3SCOL.cpp:5150
static std::string curentUID()
return the current UID WITHOUT incrementing the UID.
static std::string cleanString(std::string str, bool toLower=true, bool clASCII=true, bool clSpaces=true, bool bUID=true)
Clean a string.
void generateSubMesh(Ogre::MeshPtr ogMesh)
Definition ALMesh.cpp:210
Ogre::MeshPtr generateMesh()
Definition ALMesh.cpp:61
ALMesh(aiNode *meNode, ALScene *alscene)
Definition ALMesh.cpp:22
void makeVertexBuffer(aiMesh *asSubMesh, Ogre::SubMesh *ogSubMesh)
Definition ALMesh.cpp:416
void makeIndexBuffer(aiMesh *asSubMesh, Ogre::SubMesh *ogSubMesh)
Definition ALMesh.cpp:351
SEntity * load()
Definition ALMesh.cpp:746
void saveMesh(Ogre::MeshPtr ogMesh, boost::filesystem::path path, tinyxml2::XMLElement *parent)
Definition ALMesh.cpp:639
void convert(boost::filesystem::path expPath, tinyxml2::XMLElement *parent)
Definition ALMesh.cpp:740
std::string getRessourceGroup()
Definition ALScene.cpp:497
const std::vector< std::string > getMaterialNames()
Definition ALScene.cpp:50
aiMatrix4x4 getFullTransform(aiNode *toThis)
Definition ALScene.cpp:60
SScene * getSScene()
Definition ALScene.cpp:487
ALSceneLoader * GetSceneLoader()
Definition ALScene.h:98
const aiScene * getAiScene()
Definition ALScene.cpp:492
std::string getSceneName()
Definition ALScene.cpp:507
bool isBone(aiNode *node)
Check if a node is a bone.
Definition ALScene.cpp:517
unsigned int getFlags()
void addBone(aiNode *node, aiBone *bone, Ogre::SubMesh *submesh)
void makeHierarchy(aiMatrix4x4 meshInverseTrans)
void processAnimation()
void SetLogEnable(const bool &state)
Definition SO3Root.cpp:374
bool GetLogEnable()
Definition SO3Root.cpp:379
static SRoot * getSingletonPtr()
Definition SO3Root.cpp:111
SEntity * CreateEntity(const std::string &groupName, const std::string &newEntityName, const std::string &meshName, bool loadInBackground=false)
Definition SO3Scene.cpp:665
XMLElement * NewElement(const char *name)
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition tinyxml2.h:1303
const XMLDocument * GetDocument() const
Get the XMLDocument that owns this XMLNode.
Definition tinyxml2.h:592
XMLNode * InsertEndChild(XMLNode *addThis)