Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / shape2obj / main.cpp
blobd956392bfca097e8cf8c172a186866c47a1afa92
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2021 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <nel/misc/file.h>
21 #include <nel/3d/mesh.h>
22 #include <nel/3d/mesh_mrm.h>
23 #include <nel/3d/mesh_mrm_skinned.h>
24 #include <nel/3d/scene.h>
25 #include <nel/3d/register_3d.h>
26 #include <nel/misc/app_context.h>
27 #include <nel/misc/o_xml.h>
28 #include <nel/misc/i_xml.h>
30 #include <fstream>
31 #include <iostream>
33 using namespace NLMISC;
34 using namespace NL3D;
35 using namespace std;
37 struct CVertex
39 CVector vertex;
40 CVector normal;
41 CUV uv;
44 bool operator == (const CVertex &v1, const CVertex &v2)
46 return (v1.vertex == v2.vertex) && (v1.normal == v2.normal) && (v1.uv == v2.uv);
49 bool operator < (const CVertex &v1, const CVertex &v2)
52 if (v1.vertex == v2.vertex)
54 if (v1.normal == v2.normal)
56 return (v1.uv < v2.uv);
58 return (v1.normal < v1.normal);
61 return (v1.vertex < v2.vertex);
64 const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshGeom *mesh, uint lodId, uint renderPass)
66 return &(mesh->getRdrPassPrimitiveBlock(lodId, renderPass));
69 const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMGeom *mesh, uint lodId, uint renderPass)
71 return &(mesh->getRdrPassPrimitiveBlock(lodId, renderPass));
74 // ***************************************************************************
76 const CIndexBuffer *getRdrPassPrimitiveBlock(const CMeshMRMSkinnedGeom *mesh, uint lodId, uint renderPass)
78 static CIndexBuffer block;
79 mesh->getRdrPassPrimitiveBlock(lodId, renderPass, block);
80 return &block;
83 // ***************************************************************************
85 bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh);
86 bool ProcessMeshMRM(const std::string &filename, IShape *shapeMesh);
87 bool ProcessMesh(const std::string &filename, IShape *shapeMesh);
89 int main(int argc, char* argv[])
91 if (argc < 2)
93 cout << "Syntax : shape2obj <NeL .shape file>" << endl;
95 return 1;
98 if (!NLMISC::INelContext::isContextInitialised()) new NLMISC::CApplicationContext();
100 registerSerial3d();
101 CScene::registerBasics();
103 IShape *shapeMesh = NULL;
105 CIFile ifile;
107 // Sream a shape
108 CShapeStream streamShape;
110 string filename = argv[1];
112 if (!ifile.open(filename)) return 1;
116 // Stream it
117 streamShape.serial(ifile);
119 // Add the shape
120 shapeMesh = streamShape.getShapePointer();
122 catch (const Exception& e)
124 cout << "Error : " << e.what() << endl;
126 return 1;
129 if (ProcessMeshMRMSkinned(filename, shapeMesh)) return 0;
130 if (ProcessMeshMRM(filename, shapeMesh)) return 0;
131 if (ProcessMesh(filename, shapeMesh)) return 0;
133 return 1;
136 bool ProcessMeshMRMSkinned(const std::string &filename, IShape *shapeMesh)
138 CMeshMRMSkinned *mesh = dynamic_cast<CMeshMRMSkinned*>(shapeMesh);
140 if (!mesh) return false;
142 COFile ofile;
144 CMeshMRMSkinnedGeom* meshIn = (CMeshMRMSkinnedGeom*)&mesh->getMeshGeom();
146 std::vector<CMesh::CSkinWeight> skinWeights;
147 meshIn->getSkinWeights(skinWeights);
148 CVertexBuffer vertexBuffer;
149 meshIn->getVertexBuffer(vertexBuffer);
151 CVertexBufferRead vba;
152 vertexBuffer.lock (vba);
153 uint i, j;
155 // **** Select the Lod.
156 uint numLods= meshIn->getNbLod();
158 // get the max tris displayed
159 float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
160 float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
161 // find the lod
162 sint lodId = numLods-1;
164 // **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
165 vector<sint> vertexUsed;
166 // -1 means "not used"
167 vertexUsed.resize(skinWeights.size(), -1);
168 // Parse all triangles.
169 for(i=0;i<meshIn->getNbRdrPass(lodId); ++i)
171 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
172 CIndexBufferRead iba;
173 pb->lock (iba);
174 if (iba.getFormat() == CIndexBuffer::Indices32)
176 const uint32 *triPtr= (const uint32 *) iba.getPtr();
177 for(j=0;j<pb->getNumIndexes(); ++j)
179 uint idx= *triPtr;
180 // Flag the vertex with its own index => used.
181 vertexUsed[idx]= idx;
182 triPtr++;
185 else
187 const uint16 *triPtr= (const uint16 *) iba.getPtr();
188 for(j=0;j<pb->getNumIndexes(); ++j)
190 uint idx= *triPtr;
191 // Flag the vertex with its own index => used.
192 vertexUsed[idx]= idx;
193 triPtr++;
197 // Special for Geomorphs: must take The End target vertex.
198 const std::vector<CMRMWedgeGeom> &geomorphs= meshIn->getGeomorphs(lodId);
199 for(i=0;i<geomorphs.size(); ++i)
201 uint trueIdx= geomorphs[i].End;
202 // map to the Geomorph Target.
203 vertexUsed[i]= trueIdx;
204 // mark also the real vertex used as used.
205 vertexUsed[trueIdx]= trueIdx;
209 // **** For all vertices used (not geomorphs), compute vertex Skins.
210 vector<CVertex> shadowVertices;
211 vector<sint> vertexToVSkin;
212 vertexToVSkin.resize(vertexUsed.size());
213 shadowVertices.reserve(vertexUsed.size());
214 // use a map to remove duplicates (because of UV/normal discontinuities before!!)
215 map<CVertex, uint> shadowVertexMap;
216 uint numMerged= 0;
217 // Skip Geomorphs.
218 for(i=geomorphs.size();i<vertexUsed.size(); ++i)
220 // If this vertex is used.
221 if(vertexUsed[i]!=-1)
223 // Build the vertex
224 CVertex shadowVert;
225 CUV uv;
226 shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
227 shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
228 shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
230 // Select the best Matrix.
231 CMesh::CSkinWeight sw= skinWeights[i];
232 float maxW= 0;
233 uint matId= 0;
234 for(j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
236 // if no more matrix influenced, stop
237 if(sw.Weights[j]==0)
238 break;
239 if(sw.Weights[j]>maxW)
241 matId= sw.MatrixId[j];
242 maxW= sw.Weights[j];
245 // shadowVert.MatrixId= matId;
247 // If dont find the shadowVertex in the map.
248 map<CVertex, uint>::iterator it= shadowVertexMap.find(shadowVert);
249 if(it==shadowVertexMap.end())
251 // Append
252 uint index= shadowVertices.size();
253 vertexToVSkin[i]= index;
254 shadowVertices.push_back(shadowVert);
255 shadowVertexMap.insert(make_pair(shadowVert, index));
257 else
259 // Ok, map.
260 vertexToVSkin[i]= it->second;
261 numMerged++;
267 ofstream ofs(string(filename + ".obj").c_str());
269 for(size_t y = 0; y < shadowVertices.size(); ++y)
271 CVector v = shadowVertices[y].vertex;
272 CVector vn = shadowVertices[y].normal;
273 CUV vt = shadowVertices[y].uv;
275 ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
276 ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
277 ofs << "vt " << vt.U << " " << (1.0f - vt.V) << endl;
280 // **** Get All Faces
281 // Final List Of Triangles that match the bone.
282 vector<uint32> shadowTriangles;
283 shadowTriangles.reserve(1000);
284 // Parse all input tri of the mesh.
285 for(i=0; i<meshIn->getNbRdrPass(lodId); ++i)
287 ofs << "g pass" << i << endl;
289 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
290 CIndexBufferRead iba;
291 pb->lock (iba);
292 if (iba.getFormat() == CIndexBuffer::Indices32)
294 const uint32 *triPtr= (const uint32 *) iba.getPtr();
296 for(j=0; j<pb->getNumIndexes(); ++j)
298 uint idx= *triPtr;
299 // Get the real Vertex (ie not the geomporhed one).
300 idx= vertexUsed[idx];
301 // Get the ShadowVertex associated
302 idx= vertexToVSkin[idx];
304 shadowTriangles.push_back(idx);
305 triPtr++;
308 else
310 const uint16 *triPtr= (const uint16 *) iba.getPtr();
311 for(j=0; j<pb->getNumIndexes(); ++j)
313 uint idx= *triPtr;
314 // Get the real Vertex (ie not the geomporhed one).
315 idx= vertexUsed[idx];
316 // Get the ShadowVertex associated
317 idx= vertexToVSkin[idx];
319 shadowTriangles.push_back(idx);
320 triPtr++;
324 for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
326 ofs << "f " << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
327 ofs << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
328 ofs << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
331 shadowTriangles.clear();
334 ofs.close();
336 return true;
339 bool ProcessMeshMRM(const std::string &filename, IShape *shapeMesh)
341 CMeshMRM *mesh = dynamic_cast<CMeshMRM*>(shapeMesh);
343 if (!mesh) return false;
345 COFile ofile;
347 CMeshMRMGeom* meshIn = (CMeshMRMGeom*)&mesh->getMeshGeom();
349 std::vector<CMesh::CSkinWeight> skinWeights = meshIn->getSkinWeights();
350 CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
352 CVertexBufferRead vba;
353 vertexBuffer.lock (vba);
354 uint i, j;
356 // **** Select the Lod.
357 uint numLods= meshIn->getNbLod();
359 // get the max tris displayed
360 float numMeshFacesMin= (float)meshIn->getLevelDetail().MinFaceUsed;
361 float numMeshFacesMax= (float)meshIn->getLevelDetail().MaxFaceUsed;
362 // find the lod
363 sint lodId = numLods-1;
365 // **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
366 vector<sint> vertexUsed;
367 // -1 means "not used"
368 vertexUsed.resize(skinWeights.size(), -1);
369 // Parse all triangles.
370 for(i=0;i<meshIn->getNbRdrPass(lodId); ++i)
372 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
373 CIndexBufferRead iba;
374 pb->lock (iba);
375 if (iba.getFormat() == CIndexBuffer::Indices32)
377 const uint32 *triPtr= (const uint32 *) iba.getPtr();
378 for(j=0;j<pb->getNumIndexes(); ++j)
380 uint idx= *triPtr;
381 // Flag the vertex with its own index => used.
382 vertexUsed[idx]= idx;
383 triPtr++;
386 else
388 const uint16 *triPtr= (const uint16 *) iba.getPtr();
389 for(j=0;j<pb->getNumIndexes(); ++j)
391 uint idx= *triPtr;
392 // Flag the vertex with its own index => used.
393 vertexUsed[idx]= idx;
394 triPtr++;
398 // Special for Geomorphs: must take The End target vertex.
399 const std::vector<CMRMWedgeGeom> &geomorphs= meshIn->getGeomorphs(lodId);
400 for(i=0;i<geomorphs.size(); ++i)
402 uint trueIdx= geomorphs[i].End;
403 // map to the Geomorph Target.
404 vertexUsed[i]= trueIdx;
405 // mark also the real vertex used as used.
406 vertexUsed[trueIdx]= trueIdx;
410 // **** For all vertices used (not geomorphs), compute vertex Skins.
411 vector<CVertex> shadowVertices;
412 vector<sint> vertexToVSkin;
413 vertexToVSkin.resize(vertexUsed.size());
414 shadowVertices.reserve(vertexUsed.size());
415 // use a map to remove duplicates (because of UV/normal discontinuities before!!)
416 map<CVertex, uint> shadowVertexMap;
417 uint numMerged= 0;
418 // Skip Geomorphs.
419 for(i=geomorphs.size();i<vertexUsed.size(); ++i)
421 // If this vertex is used.
422 if(vertexUsed[i]!=-1)
424 // Build the vertex
425 CVertex shadowVert;
426 CUV uv;
427 shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
428 shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
429 shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
431 // Select the best Matrix.
432 CMesh::CSkinWeight sw= skinWeights[i];
433 float maxW= 0;
434 uint matId= 0;
435 for(j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
437 // if no more matrix influenced, stop
438 if(sw.Weights[j]==0)
439 break;
440 if(sw.Weights[j]>maxW)
442 matId= sw.MatrixId[j];
443 maxW= sw.Weights[j];
446 // shadowVert.MatrixId= matId;
448 // If dont find the shadowVertex in the map.
449 map<CVertex, uint>::iterator it= shadowVertexMap.find(shadowVert);
450 if(it==shadowVertexMap.end())
452 // Append
453 uint index= shadowVertices.size();
454 vertexToVSkin[i]= index;
455 shadowVertices.push_back(shadowVert);
456 shadowVertexMap.insert(make_pair(shadowVert, index));
458 else
460 // Ok, map.
461 vertexToVSkin[i]= it->second;
462 numMerged++;
468 ofstream ofs(string(filename + ".obj").c_str());
470 for(size_t y = 0; y < shadowVertices.size(); ++y)
472 CVector v = shadowVertices[y].vertex;
473 CVector vn = shadowVertices[y].normal;
474 CUV vt = shadowVertices[y].uv;
476 ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
477 ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
478 ofs << "vt " << vt.U << " " << (1.0f - vt.V) << endl;
481 // **** Get All Faces
482 // Final List Of Triangles that match the bone.
483 vector<uint32> shadowTriangles;
484 shadowTriangles.reserve(1000);
485 // Parse all input tri of the mesh.
486 for(i=0; i<meshIn->getNbRdrPass(lodId); ++i)
488 ofs << "g pass" << i << endl;
490 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, lodId, i);
491 CIndexBufferRead iba;
492 pb->lock (iba);
493 if (iba.getFormat() == CIndexBuffer::Indices32)
495 const uint32 *triPtr= (const uint32 *) iba.getPtr();
497 for(j=0; j<pb->getNumIndexes(); ++j)
499 uint idx= *triPtr;
500 // Get the real Vertex (ie not the geomporhed one).
501 idx= vertexUsed[idx];
502 // Get the ShadowVertex associated
503 idx= vertexToVSkin[idx];
505 shadowTriangles.push_back(idx);
506 triPtr++;
509 else
511 const uint16 *triPtr= (const uint16 *) iba.getPtr();
512 for(j=0; j<pb->getNumIndexes(); ++j)
514 uint idx= *triPtr;
515 // Get the real Vertex (ie not the geomporhed one).
516 idx= vertexUsed[idx];
517 // Get the ShadowVertex associated
518 idx= vertexToVSkin[idx];
520 shadowTriangles.push_back(idx);
521 triPtr++;
525 for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
527 ofs << "f " << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
528 ofs << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
529 ofs << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
532 shadowTriangles.clear();
535 ofs.close();
537 return true;
541 bool ProcessMesh(const std::string &filename, IShape *shapeMesh)
543 CMesh *mesh = dynamic_cast<CMesh*>(shapeMesh);
545 if (!mesh) return false;
547 COFile ofile;
549 const CMeshGeom *meshIn = &mesh->getMeshGeom();
551 CVertexBuffer vertexBuffer = meshIn->getVertexBuffer();
553 CVertexBufferRead vba;
554 vertexBuffer.lock (vba);
555 uint i, j;
557 // **** First, for the best lod indicate what vertex is used or not. Also index geomorphs to know what real vertex is used
558 vector<sint> vertexUsed;
559 // -1 means "not used"
560 vertexUsed.resize(vertexBuffer.capacity(), -1);
561 // Parse all triangles.
562 for(i=0;i<meshIn->getNbRdrPass(0); ++i)
564 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, 0, i);
565 CIndexBufferRead iba;
566 pb->lock (iba);
567 if (iba.getFormat() == CIndexBuffer::Indices32)
569 const uint32 *triPtr= (const uint32 *) iba.getPtr();
570 for(j=0;j<pb->getNumIndexes(); ++j)
572 uint idx= *triPtr;
573 // Flag the vertex with its own index => used.
574 vertexUsed[idx]= idx;
575 triPtr++;
578 else
580 const uint16 *triPtr= (const uint16 *) iba.getPtr();
581 for(j=0;j<pb->getNumIndexes(); ++j)
583 uint idx= *triPtr;
584 // Flag the vertex with its own index => used.
585 vertexUsed[idx]= idx;
586 triPtr++;
592 // **** For all vertices used (not geomorphs), compute vertex Skins.
593 vector<CVertex> shadowVertices;
594 vector<sint> vertexToVSkin;
595 vertexToVSkin.resize(vertexUsed.size());
596 shadowVertices.reserve(vertexUsed.size());
598 for(i=0;i<vertexUsed.size(); ++i)
600 // If this vertex is used.
601 if(vertexUsed[i]!=-1)
603 // Build the vertex
604 CVertex shadowVert;
605 CUV uv;
606 shadowVert.vertex = *(CVector*)vba.getVertexCoordPointer(i);
607 shadowVert.normal = *(CVector*)vba.getNormalCoordPointer(i);
608 shadowVert.uv = *(CUV*)vba.getTexCoordPointer(i);
610 // Append
611 uint index= shadowVertices.size();
612 vertexToVSkin[i]= index;
613 shadowVertices.push_back(shadowVert);
617 ofstream ofs(string(filename + ".obj").c_str());
619 map<CVector, sint> weldedVerticesToId;
620 vector<CVector> weldedVertices;
621 vector<sint> shadowToWelded;
622 weldedVertices.reserve(shadowVertices.size());
623 shadowToWelded.resize(shadowVertices.size());
625 for (i = 0; i < shadowVertices.size(); ++i)
627 CVector v = shadowVertices[i].vertex;
628 map<CVector, sint>::iterator it = weldedVerticesToId.find(v);
629 if (it == weldedVerticesToId.end())
631 weldedVerticesToId[v] = weldedVertices.size();
632 shadowToWelded[i] = weldedVertices.size();
633 weldedVertices.push_back(v);
635 else
637 shadowToWelded[i] = it->second;
641 for(size_t y = 0; y < weldedVertices.size(); ++y)
643 CVector v = weldedVertices[y];
644 ofs << "v " << v.x << " " << v.y << " " << v.z << endl;
647 for(size_t y = 0; y < shadowVertices.size(); ++y)
649 CVector vn = shadowVertices[y].normal;
650 CUV vt = shadowVertices[y].uv;
651 ofs << "vn " << vn.x << " " << vn.y << " " << vn.z << endl;
652 ofs << "vt " << vt.U << " " << (1.0f - vt.V) << endl;
655 // **** Get All Faces
656 // Final List Of Triangles that match the bone.
657 vector<uint32> shadowTriangles;
658 shadowTriangles.reserve(1000);
659 // Parse all input tri of the mesh.
660 for(i=0; i<meshIn->getNbRdrPass(0); ++i)
662 ofs << "g " << filename << endl;
664 const CIndexBuffer *pb = getRdrPassPrimitiveBlock(meshIn, 0, i);
665 CIndexBufferRead iba;
666 pb->lock (iba);
667 if (iba.getFormat() == CIndexBuffer::Indices32)
669 const uint32 *triPtr= (const uint32 *) iba.getPtr();
671 for(j=0; j<pb->getNumIndexes(); ++j)
673 uint idx= *triPtr;
674 // Get the real Vertex (ie not the geomporhed one).
675 idx= vertexUsed[idx];
676 // Get the ShadowVertex associated
677 idx= vertexToVSkin[idx];
679 shadowTriangles.push_back(idx);
680 triPtr++;
683 else
685 const uint16 *triPtr= (const uint16 *) iba.getPtr();
686 for(j=0; j<pb->getNumIndexes(); ++j)
688 uint idx= *triPtr;
689 // Get the real Vertex (ie not the geomporhed one).
690 idx= vertexUsed[idx];
691 // Get the ShadowVertex associated
692 idx= vertexToVSkin[idx];
694 shadowTriangles.push_back(idx);
695 triPtr++;
699 for(size_t pass = 0; pass<shadowTriangles.size(); pass += 3)
701 ofs << "f " << shadowToWelded[shadowTriangles[pass]]+1 << "/" << shadowTriangles[pass]+1 << "/" << shadowTriangles[pass]+1 << " ";
702 ofs << shadowToWelded[shadowTriangles[pass+1]]+1 << "/" << shadowTriangles[pass+1]+1 << "/" << shadowTriangles[pass+1]+1 << " ";
703 ofs << shadowToWelded[shadowTriangles[pass+2]]+1 << "/" << shadowTriangles[pass+2]+1 << "/" << shadowTriangles[pass+2]+1 << endl;
706 shadowTriangles.clear();
709 ofs.close();
711 return true;