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