1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2016, assimp team
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13 
14 * Redistributions of source code must retain the above
15   copyright notice, this list of conditions and the
16   following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19   copyright notice, this list of conditions and the
20   following disclaimer in the documentation and/or other
21   materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24   contributors may be used to endorse or promote products
25   derived from this software without specific prior
26   written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 
42 /** @file  NDOLoader.cpp
43  *  Implementation of the NDO importer class.
44  */
45 
46 
47 #ifndef ASSIMP_BUILD_NO_NDO_IMPORTER
48 #include "NDOLoader.h"
49 #include <assimp/DefaultLogger.hpp>
50 #include <assimp/IOSystem.hpp>
51 #include <assimp/scene.h>
52 #include "StreamReader.h"
53 
54 using namespace Assimp;
55 
56 static const aiImporterDesc desc = {
57     "Nendo Mesh Importer",
58     "",
59     "",
60     "http://www.izware.com/nendo/index.htm",
61     aiImporterFlags_SupportBinaryFlavour,
62     0,
63     0,
64     0,
65     0,
66     "ndo"
67 };
68 
69 // ------------------------------------------------------------------------------------------------
70 // Constructor to be privately used by Importer
NDOImporter()71 NDOImporter::NDOImporter()
72 {}
73 
74 // ------------------------------------------------------------------------------------------------
75 // Destructor, private as well
~NDOImporter()76 NDOImporter::~NDOImporter()
77 {}
78 
79 // ------------------------------------------------------------------------------------------------
80 // Returns whether the class can handle the format of the given file.
CanRead(const std::string & pFile,IOSystem * pIOHandler,bool checkSig) const81 bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
82 {
83     // check file extension
84     const std::string extension = GetExtension(pFile);
85 
86     if( extension == "ndo")
87         return true;
88 
89     if ((checkSig || !extension.length()) && pIOHandler) {
90         const char* tokens[] = {"nendo"};
91         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,5);
92     }
93     return false;
94 }
95 
96 // ------------------------------------------------------------------------------------------------
97 // Build a string of all file extensions supported
GetInfo() const98 const aiImporterDesc* NDOImporter::GetInfo () const
99 {
100     return &desc;
101 }
102 
103 // ------------------------------------------------------------------------------------------------
104 // Setup configuration properties for the loader
SetupProperties(const Importer *)105 void NDOImporter::SetupProperties(const Importer* /*pImp*/)
106 {
107     // nothing to be done for the moment
108 }
109 
110 // ------------------------------------------------------------------------------------------------
111 // Imports the given file into the given scene structure.
InternReadFile(const std::string & pFile,aiScene * pScene,IOSystem * pIOHandler)112 void NDOImporter::InternReadFile( const std::string& pFile,
113     aiScene* pScene, IOSystem* pIOHandler)
114 {
115     StreamReaderBE reader(pIOHandler->Open( pFile, "rb"));
116 
117     // first 9 bytes are nendo file format ("nendo 1.n")
118     const char* head = (const char*)reader.GetPtr();
119     reader.IncPtr(9);
120 
121     if (strncmp("nendo ",head,6)) {
122         throw DeadlyImportError("Not a Nendo file; magic signature missing");
123     }
124     // check if this is a supported version. if not, continue, too -- users,
125     // please don't complain if it doesn't work then ...
126     unsigned int file_format = 12;
127     if (!strncmp("1.0",head+6,3)) {
128         file_format = 10;
129         DefaultLogger::get()->info("NDO file format is 1.0");
130     }
131     else if (!strncmp("1.1",head+6,3)) {
132         file_format = 11;
133         DefaultLogger::get()->info("NDO file format is 1.1");
134     }
135     else if (!strncmp("1.2",head+6,3)) {
136         file_format = 12;
137         DefaultLogger::get()->info("NDO file format is 1.2");
138     }
139     else {
140         DefaultLogger::get()->warn(std::string("Unrecognized nendo file format version, continuing happily ... :") + (head+6));
141     }
142 
143     reader.IncPtr(2); /* skip flags */
144     if (file_format >= 12) {
145         reader.IncPtr(2);
146     }
147     unsigned int temp = reader.GetU1();
148 
149     std::vector<Object> objects(temp); /* buffer to store all the loaded objects in */
150 
151     // read all objects
152     for (unsigned int o = 0; o < objects.size(); ++o) {
153 
154 //      if (file_format < 12) {
155             if (!reader.GetI1()) {
156                 continue; /* skip over empty object */
157             }
158         //  reader.GetI2();
159 //      }
160         Object& obj = objects[o];
161 
162         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
163         head = (const char*)reader.GetPtr();
164         reader.IncPtr(temp + 76); /* skip unknown stuff */
165 
166         obj.name = std::string(head, temp);
167 
168         // read edge table
169         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
170         obj.edges.reserve(temp);
171         for (unsigned int e = 0; e < temp; ++e) {
172 
173             obj.edges.push_back(Edge());
174             Edge& edge = obj.edges.back();
175 
176             for (unsigned int i = 0; i< 8; ++i) {
177                 edge.edge[i] = file_format >= 12 ? reader.GetU4() : reader.GetU2();
178             }
179             edge.hard =  file_format >= 11 ? reader.GetU1() : 0;
180             for (unsigned int i = 0; i< 8; ++i) {
181                 edge.color[i] = reader.GetU1();
182             }
183         }
184 
185         // read face table
186         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
187         obj.faces.reserve(temp);
188         for (unsigned int e = 0; e < temp; ++e) {
189 
190             obj.faces.push_back(Face());
191             Face& face = obj.faces.back();
192 
193             face.elem = file_format >= 12 ? reader.GetU4() : reader.GetU2();
194         }
195 
196         // read vertex table
197         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
198         obj.vertices.reserve(temp);
199         for (unsigned int e = 0; e < temp; ++e) {
200 
201             obj.vertices.push_back(Vertex());
202             Vertex& v = obj.vertices.back();
203 
204             v.num = file_format >= 12 ? reader.GetU4() : reader.GetU2();
205             v.val.x = reader.GetF4();
206             v.val.y = reader.GetF4();
207             v.val.z = reader.GetF4();
208         }
209 
210         // read UVs
211         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
212         for (unsigned int e = 0; e < temp; ++e) {
213              file_format >= 12 ? reader.GetU4() : reader.GetU2();
214         }
215 
216         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
217         for (unsigned int e = 0; e < temp; ++e) {
218              file_format >= 12 ? reader.GetU4() : reader.GetU2();
219         }
220 
221         if (reader.GetU1()) {
222             const unsigned int x = reader.GetU2(), y = reader.GetU2();
223             temp = 0;
224             while (temp < x*y)  {
225                 unsigned int repeat = reader.GetU1();
226                 reader.GetU1();
227                 reader.GetU1();
228                 reader.GetU1();
229                 temp += repeat;
230             }
231         }
232     }
233 
234     // construct a dummy node graph and add all named objects as child nodes
235     aiNode* root = pScene->mRootNode = new aiNode("$NDODummyRoot");
236     aiNode** cc = root->mChildren = new aiNode* [ root->mNumChildren = static_cast<unsigned int>( objects.size()) ] ();
237     pScene->mMeshes = new aiMesh* [ root->mNumChildren] ();
238 
239     std::vector<aiVector3D> vertices;
240     std::vector<unsigned int> indices;
241 
242     for(const Object& obj : objects) {
243         aiNode* nd = *cc++ = new aiNode(obj.name);
244         nd->mParent = root;
245 
246         // translated from a python dict() - a vector might be sufficient as well
247         typedef std::map<unsigned int, unsigned int>  FaceTable;
248         FaceTable face_table;
249 
250         unsigned int n = 0;
251         for(const Edge& edge : obj.edges) {
252 
253             face_table[edge.edge[2]] = n;
254             face_table[edge.edge[3]] = n;
255 
256             ++n;
257         }
258 
259         aiMesh* mesh = new aiMesh();
260         aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces=face_table.size()];
261 
262         vertices.clear();
263         vertices.reserve(4 * face_table.size()); // arbitrarily chosen
264         for(FaceTable::value_type& v : face_table) {
265             indices.clear();
266 
267             aiFace& f = *faces++;
268 
269             const unsigned int key = v.first;
270             unsigned int cur_edge = v.second;
271             while (1) {
272                 unsigned int next_edge, next_vert;
273                 if (key == obj.edges[cur_edge].edge[3]) {
274                     next_edge = obj.edges[cur_edge].edge[5];
275                     next_vert = obj.edges[cur_edge].edge[1];
276                 }
277                 else {
278                     next_edge = obj.edges[cur_edge].edge[4];
279                     next_vert = obj.edges[cur_edge].edge[0];
280                 }
281                 indices.push_back( vertices.size() );
282                 vertices.push_back(obj.vertices[ next_vert ].val);
283 
284                 cur_edge = next_edge;
285                 if (cur_edge == v.second) {
286                     break;
287                 }
288             }
289 
290             f.mIndices = new unsigned int[f.mNumIndices = indices.size()];
291             std::copy(indices.begin(),indices.end(),f.mIndices);
292         }
293 
294         mesh->mVertices = new aiVector3D[mesh->mNumVertices = vertices.size()];
295         std::copy(vertices.begin(),vertices.end(),mesh->mVertices);
296 
297         if (mesh->mNumVertices) {
298             pScene->mMeshes[pScene->mNumMeshes] = mesh;
299 
300             (nd->mMeshes = new unsigned int[nd->mNumMeshes=1])[0]=pScene->mNumMeshes++;
301         }
302     }
303 }
304 
305 #endif
306