rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file Implementation of the STL importer class */
|
nuclear@0
|
43
|
nuclear@0
|
44 #include "AssimpPCH.h"
|
nuclear@0
|
45 #ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
|
nuclear@0
|
46
|
nuclear@0
|
47 // internal headers
|
nuclear@0
|
48 #include "NFFLoader.h"
|
nuclear@0
|
49 #include "ParsingUtils.h"
|
nuclear@0
|
50 #include "StandardShapes.h"
|
nuclear@0
|
51 #include "fast_atof.h"
|
nuclear@0
|
52 #include "RemoveComments.h"
|
nuclear@0
|
53
|
nuclear@0
|
54 using namespace Assimp;
|
nuclear@0
|
55
|
nuclear@0
|
56 static const aiImporterDesc desc = {
|
nuclear@0
|
57 "Neutral File Format Importer",
|
nuclear@0
|
58 "",
|
nuclear@0
|
59 "",
|
nuclear@0
|
60 "",
|
nuclear@0
|
61 aiImporterFlags_SupportBinaryFlavour,
|
nuclear@0
|
62 0,
|
nuclear@0
|
63 0,
|
nuclear@0
|
64 0,
|
nuclear@0
|
65 0,
|
nuclear@0
|
66 "enff nff"
|
nuclear@0
|
67 };
|
nuclear@0
|
68
|
nuclear@0
|
69 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
70 // Constructor to be privately used by Importer
|
nuclear@0
|
71 NFFImporter::NFFImporter()
|
nuclear@0
|
72 {}
|
nuclear@0
|
73
|
nuclear@0
|
74 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
75 // Destructor, private as well
|
nuclear@0
|
76 NFFImporter::~NFFImporter()
|
nuclear@0
|
77 {}
|
nuclear@0
|
78
|
nuclear@0
|
79 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
80 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
81 bool NFFImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const
|
nuclear@0
|
82 {
|
nuclear@0
|
83 return SimpleExtensionCheck(pFile,"nff","enff");
|
nuclear@0
|
84 }
|
nuclear@0
|
85
|
nuclear@0
|
86 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
87 // Get the list of all supported file extensions
|
nuclear@0
|
88 const aiImporterDesc* NFFImporter::GetInfo () const
|
nuclear@0
|
89 {
|
nuclear@0
|
90 return &desc;
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
94 #define AI_NFF_PARSE_FLOAT(f) \
|
nuclear@0
|
95 SkipSpaces(&sz); \
|
nuclear@0
|
96 if (!::IsLineEnd(*sz))sz = fast_atoreal_move<float>(sz, (float&)f);
|
nuclear@0
|
97
|
nuclear@0
|
98 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
99 #define AI_NFF_PARSE_TRIPLE(v) \
|
nuclear@0
|
100 AI_NFF_PARSE_FLOAT(v[0]) \
|
nuclear@0
|
101 AI_NFF_PARSE_FLOAT(v[1]) \
|
nuclear@0
|
102 AI_NFF_PARSE_FLOAT(v[2])
|
nuclear@0
|
103
|
nuclear@0
|
104 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
105 #define AI_NFF_PARSE_SHAPE_INFORMATION() \
|
nuclear@0
|
106 aiVector3D center, radius(1.0f,get_qnan(),get_qnan()); \
|
nuclear@0
|
107 AI_NFF_PARSE_TRIPLE(center); \
|
nuclear@0
|
108 AI_NFF_PARSE_TRIPLE(radius); \
|
nuclear@0
|
109 if (is_qnan(radius.z))radius.z = radius.x; \
|
nuclear@0
|
110 if (is_qnan(radius.y))radius.y = radius.x; \
|
nuclear@0
|
111 currentMesh.radius = radius; \
|
nuclear@0
|
112 currentMesh.center = center;
|
nuclear@0
|
113
|
nuclear@0
|
114 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
115 #define AI_NFF2_GET_NEXT_TOKEN() \
|
nuclear@0
|
116 do \
|
nuclear@0
|
117 { \
|
nuclear@0
|
118 if (!GetNextLine(buffer,line)) \
|
nuclear@0
|
119 {DefaultLogger::get()->warn("NFF2: Unexpected EOF, can't read next token");break;} \
|
nuclear@0
|
120 SkipSpaces(line,&sz); \
|
nuclear@0
|
121 } \
|
nuclear@0
|
122 while(IsLineEnd(*sz))
|
nuclear@0
|
123
|
nuclear@0
|
124
|
nuclear@0
|
125 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
126 // Loads the materail table for the NFF2 file format from an external file
|
nuclear@0
|
127 void NFFImporter::LoadNFF2MaterialTable(std::vector<ShadingInfo>& output,
|
nuclear@0
|
128 const std::string& path, IOSystem* pIOHandler)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 boost::scoped_ptr<IOStream> file( pIOHandler->Open( path, "rb"));
|
nuclear@0
|
131
|
nuclear@0
|
132 // Check whether we can read from the file
|
nuclear@0
|
133 if( !file.get()) {
|
nuclear@0
|
134 DefaultLogger::get()->error("NFF2: Unable to open material library " + path + ".");
|
nuclear@0
|
135 return;
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 // get the size of the file
|
nuclear@0
|
139 const unsigned int m = (unsigned int)file->FileSize();
|
nuclear@0
|
140
|
nuclear@0
|
141 // allocate storage and copy the contents of the file to a memory buffer
|
nuclear@0
|
142 // (terminate it with zero)
|
nuclear@0
|
143 std::vector<char> mBuffer2(m+1);
|
nuclear@0
|
144 TextFileToBuffer(file.get(),mBuffer2);
|
nuclear@0
|
145 const char* buffer = &mBuffer2[0];
|
nuclear@0
|
146
|
nuclear@0
|
147 // First of all: remove all comments from the file
|
nuclear@0
|
148 CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
|
nuclear@0
|
149
|
nuclear@0
|
150 // The file should start with the magic sequence "mat"
|
nuclear@0
|
151 if (!TokenMatch(buffer,"mat",3)) {
|
nuclear@0
|
152 DefaultLogger::get()->error("NFF2: Not a valid material library " + path + ".");
|
nuclear@0
|
153 return;
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 ShadingInfo* curShader = NULL;
|
nuclear@0
|
157
|
nuclear@0
|
158 // No read the file line per line
|
nuclear@0
|
159 char line[4096];
|
nuclear@0
|
160 const char* sz;
|
nuclear@0
|
161 while (GetNextLine(buffer,line))
|
nuclear@0
|
162 {
|
nuclear@0
|
163 SkipSpaces(line,&sz);
|
nuclear@0
|
164
|
nuclear@0
|
165 // 'version' defines the version of the file format
|
nuclear@0
|
166 if (TokenMatch(sz,"version",7))
|
nuclear@0
|
167 {
|
nuclear@0
|
168 DefaultLogger::get()->info("NFF (Sense8) material library file format: " + std::string(sz));
|
nuclear@0
|
169 }
|
nuclear@0
|
170 // 'matdef' starts a new material in the file
|
nuclear@0
|
171 else if (TokenMatch(sz,"matdef",6))
|
nuclear@0
|
172 {
|
nuclear@0
|
173 // add a new material to the list
|
nuclear@0
|
174 output.push_back( ShadingInfo() );
|
nuclear@0
|
175 curShader = & output.back();
|
nuclear@0
|
176
|
nuclear@0
|
177 // parse the name of the material
|
nuclear@0
|
178 }
|
nuclear@0
|
179 else if (!TokenMatch(sz,"valid",5))
|
nuclear@0
|
180 {
|
nuclear@0
|
181 // check whether we have an active material at the moment
|
nuclear@0
|
182 if (!IsLineEnd(*sz))
|
nuclear@0
|
183 {
|
nuclear@0
|
184 if (!curShader)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 DefaultLogger::get()->error(std::string("NFF2 material library: Found element ") +
|
nuclear@0
|
187 sz + "but there is no active material");
|
nuclear@0
|
188 continue;
|
nuclear@0
|
189 }
|
nuclear@0
|
190 }
|
nuclear@0
|
191 else continue;
|
nuclear@0
|
192
|
nuclear@0
|
193 // now read the material property and determine its type
|
nuclear@0
|
194 aiColor3D c;
|
nuclear@0
|
195 if (TokenMatch(sz,"ambient",7))
|
nuclear@0
|
196 {
|
nuclear@0
|
197 AI_NFF_PARSE_TRIPLE(c);
|
nuclear@0
|
198 curShader->ambient = c;
|
nuclear@0
|
199 }
|
nuclear@0
|
200 else if (TokenMatch(sz,"diffuse",7) || TokenMatch(sz,"ambientdiffuse",14) /* correct? */)
|
nuclear@0
|
201 {
|
nuclear@0
|
202 AI_NFF_PARSE_TRIPLE(c);
|
nuclear@0
|
203 curShader->diffuse = curShader->ambient = c;
|
nuclear@0
|
204 }
|
nuclear@0
|
205 else if (TokenMatch(sz,"specular",8))
|
nuclear@0
|
206 {
|
nuclear@0
|
207 AI_NFF_PARSE_TRIPLE(c);
|
nuclear@0
|
208 curShader->specular = c;
|
nuclear@0
|
209 }
|
nuclear@0
|
210 else if (TokenMatch(sz,"emission",8))
|
nuclear@0
|
211 {
|
nuclear@0
|
212 AI_NFF_PARSE_TRIPLE(c);
|
nuclear@0
|
213 curShader->emissive = c;
|
nuclear@0
|
214 }
|
nuclear@0
|
215 else if (TokenMatch(sz,"shininess",9))
|
nuclear@0
|
216 {
|
nuclear@0
|
217 AI_NFF_PARSE_FLOAT(curShader->shininess);
|
nuclear@0
|
218 }
|
nuclear@0
|
219 else if (TokenMatch(sz,"opacity",7))
|
nuclear@0
|
220 {
|
nuclear@0
|
221 AI_NFF_PARSE_FLOAT(curShader->opacity);
|
nuclear@0
|
222 }
|
nuclear@0
|
223 }
|
nuclear@0
|
224 }
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
228 // Imports the given file into the given scene structure.
|
nuclear@0
|
229 void NFFImporter::InternReadFile( const std::string& pFile,
|
nuclear@0
|
230 aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
231 {
|
nuclear@0
|
232 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
nuclear@0
|
233
|
nuclear@0
|
234 // Check whether we can read from the file
|
nuclear@0
|
235 if( !file.get())
|
nuclear@0
|
236 throw DeadlyImportError( "Failed to open NFF file " + pFile + ".");
|
nuclear@0
|
237
|
nuclear@0
|
238 unsigned int m = (unsigned int)file->FileSize();
|
nuclear@0
|
239
|
nuclear@0
|
240 // allocate storage and copy the contents of the file to a memory buffer
|
nuclear@0
|
241 // (terminate it with zero)
|
nuclear@0
|
242 std::vector<char> mBuffer2;
|
nuclear@0
|
243 TextFileToBuffer(file.get(),mBuffer2);
|
nuclear@0
|
244 const char* buffer = &mBuffer2[0];
|
nuclear@0
|
245
|
nuclear@0
|
246 // mesh arrays - separate here to make the handling of the pointers below easier.
|
nuclear@0
|
247 std::vector<MeshInfo> meshes;
|
nuclear@0
|
248 std::vector<MeshInfo> meshesWithNormals;
|
nuclear@0
|
249 std::vector<MeshInfo> meshesWithUVCoords;
|
nuclear@0
|
250 std::vector<MeshInfo> meshesLocked;
|
nuclear@0
|
251
|
nuclear@0
|
252 char line[4096];
|
nuclear@0
|
253 const char* sz;
|
nuclear@0
|
254
|
nuclear@0
|
255 // camera parameters
|
nuclear@0
|
256 aiVector3D camPos, camUp(0.f,1.f,0.f), camLookAt(0.f,0.f,1.f);
|
nuclear@0
|
257 float angle = 45.f;
|
nuclear@0
|
258 aiVector2D resolution;
|
nuclear@0
|
259
|
nuclear@0
|
260 bool hasCam = false;
|
nuclear@0
|
261
|
nuclear@0
|
262 MeshInfo* currentMeshWithNormals = NULL;
|
nuclear@0
|
263 MeshInfo* currentMesh = NULL;
|
nuclear@0
|
264 MeshInfo* currentMeshWithUVCoords = NULL;
|
nuclear@0
|
265
|
nuclear@0
|
266 ShadingInfo s; // current material info
|
nuclear@0
|
267
|
nuclear@0
|
268 // degree of tesselation
|
nuclear@0
|
269 unsigned int iTesselation = 4;
|
nuclear@0
|
270
|
nuclear@0
|
271 // some temporary variables we need to parse the file
|
nuclear@0
|
272 unsigned int sphere = 0,
|
nuclear@0
|
273 cylinder = 0,
|
nuclear@0
|
274 cone = 0,
|
nuclear@0
|
275 numNamed = 0,
|
nuclear@0
|
276 dodecahedron = 0,
|
nuclear@0
|
277 octahedron = 0,
|
nuclear@0
|
278 tetrahedron = 0,
|
nuclear@0
|
279 hexahedron = 0;
|
nuclear@0
|
280
|
nuclear@0
|
281 // lights imported from the file
|
nuclear@0
|
282 std::vector<Light> lights;
|
nuclear@0
|
283
|
nuclear@0
|
284 // check whether this is the NFF2 file format
|
nuclear@0
|
285 if (TokenMatch(buffer,"nff",3))
|
nuclear@0
|
286 {
|
nuclear@0
|
287 const float qnan = get_qnan();
|
nuclear@0
|
288 const aiColor4D cQNAN = aiColor4D (qnan,0.f,0.f,1.f);
|
nuclear@0
|
289 const aiVector3D vQNAN = aiVector3D(qnan,0.f,0.f);
|
nuclear@0
|
290
|
nuclear@0
|
291 // another NFF file format ... just a raw parser has been implemented
|
nuclear@0
|
292 // no support for further details, I don't think it is worth the effort
|
nuclear@0
|
293 // http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/nff/nff2.html
|
nuclear@0
|
294 // http://www.netghost.narod.ru/gff/graphics/summary/sense8.htm
|
nuclear@0
|
295
|
nuclear@0
|
296 // First of all: remove all comments from the file
|
nuclear@0
|
297 CommentRemover::RemoveLineComments("//",&mBuffer2[0]);
|
nuclear@0
|
298
|
nuclear@0
|
299 while (GetNextLine(buffer,line))
|
nuclear@0
|
300 {
|
nuclear@0
|
301 SkipSpaces(line,&sz);
|
nuclear@0
|
302 if (TokenMatch(sz,"version",7))
|
nuclear@0
|
303 {
|
nuclear@0
|
304 DefaultLogger::get()->info("NFF (Sense8) file format: " + std::string(sz));
|
nuclear@0
|
305 }
|
nuclear@0
|
306 else if (TokenMatch(sz,"viewpos",7))
|
nuclear@0
|
307 {
|
nuclear@0
|
308 AI_NFF_PARSE_TRIPLE(camPos);
|
nuclear@0
|
309 hasCam = true;
|
nuclear@0
|
310 }
|
nuclear@0
|
311 else if (TokenMatch(sz,"viewdir",7))
|
nuclear@0
|
312 {
|
nuclear@0
|
313 AI_NFF_PARSE_TRIPLE(camLookAt);
|
nuclear@0
|
314 hasCam = true;
|
nuclear@0
|
315 }
|
nuclear@0
|
316 // This starts a new object section
|
nuclear@0
|
317 else if (!IsSpaceOrNewLine(*sz))
|
nuclear@0
|
318 {
|
nuclear@0
|
319 unsigned int subMeshIdx = 0;
|
nuclear@0
|
320
|
nuclear@0
|
321 // read the name of the object, skip all spaces
|
nuclear@0
|
322 // at the end of it.
|
nuclear@0
|
323 const char* sz3 = sz;
|
nuclear@0
|
324 while (!IsSpaceOrNewLine(*sz))++sz;
|
nuclear@0
|
325 std::string objectName = std::string(sz3,(unsigned int)(sz-sz3));
|
nuclear@0
|
326
|
nuclear@0
|
327 const unsigned int objStart = (unsigned int)meshes.size();
|
nuclear@0
|
328
|
nuclear@0
|
329 // There could be a material table in a separate file
|
nuclear@0
|
330 std::vector<ShadingInfo> materialTable;
|
nuclear@0
|
331 while (true)
|
nuclear@0
|
332 {
|
nuclear@0
|
333 AI_NFF2_GET_NEXT_TOKEN();
|
nuclear@0
|
334
|
nuclear@0
|
335 // material table - an external file
|
nuclear@0
|
336 if (TokenMatch(sz,"mtable",6))
|
nuclear@0
|
337 {
|
nuclear@0
|
338 SkipSpaces(&sz);
|
nuclear@0
|
339 sz3 = sz;
|
nuclear@0
|
340 while (!IsSpaceOrNewLine(*sz))++sz;
|
nuclear@0
|
341 const unsigned int diff = (unsigned int)(sz-sz3);
|
nuclear@0
|
342 if (!diff)DefaultLogger::get()->warn("NFF2: Found empty mtable token");
|
nuclear@0
|
343 else
|
nuclear@0
|
344 {
|
nuclear@0
|
345 // The material table has the file extension .mat.
|
nuclear@0
|
346 // If it is not there, we need to append it
|
nuclear@0
|
347 std::string path = std::string(sz3,diff);
|
nuclear@0
|
348 if(std::string::npos == path.find_last_of(".mat"))
|
nuclear@0
|
349 {
|
nuclear@0
|
350 path.append(".mat");
|
nuclear@0
|
351 }
|
nuclear@0
|
352
|
nuclear@0
|
353 // Now extract the working directory from the path to
|
nuclear@0
|
354 // this file and append the material library filename
|
nuclear@0
|
355 // to it.
|
nuclear@0
|
356 std::string::size_type s;
|
nuclear@0
|
357 if ((std::string::npos == (s = path.find_last_of('\\')) || !s) &&
|
nuclear@0
|
358 (std::string::npos == (s = path.find_last_of('/')) || !s) )
|
nuclear@0
|
359 {
|
nuclear@0
|
360 s = pFile.find_last_of('\\');
|
nuclear@0
|
361 if (std::string::npos == s)s = pFile.find_last_of('/');
|
nuclear@0
|
362 if (std::string::npos != s)
|
nuclear@0
|
363 {
|
nuclear@0
|
364 path = pFile.substr(0,s+1) + path;
|
nuclear@0
|
365 }
|
nuclear@0
|
366 }
|
nuclear@0
|
367 LoadNFF2MaterialTable(materialTable,path,pIOHandler);
|
nuclear@0
|
368 }
|
nuclear@0
|
369 }
|
nuclear@0
|
370 else break;
|
nuclear@0
|
371 }
|
nuclear@0
|
372
|
nuclear@0
|
373 // read the numbr of vertices
|
nuclear@0
|
374 unsigned int num = ::strtoul10(sz,&sz);
|
nuclear@0
|
375
|
nuclear@0
|
376 // temporary storage
|
nuclear@0
|
377 std::vector<aiColor4D> tempColors;
|
nuclear@0
|
378 std::vector<aiVector3D> tempPositions,tempTextureCoords,tempNormals;
|
nuclear@0
|
379
|
nuclear@0
|
380 bool hasNormals = false,hasUVs = false,hasColor = false;
|
nuclear@0
|
381
|
nuclear@0
|
382 tempPositions.reserve (num);
|
nuclear@0
|
383 tempColors.reserve (num);
|
nuclear@0
|
384 tempNormals.reserve (num);
|
nuclear@0
|
385 tempTextureCoords.reserve (num);
|
nuclear@0
|
386 for (unsigned int i = 0; i < num; ++i)
|
nuclear@0
|
387 {
|
nuclear@0
|
388 AI_NFF2_GET_NEXT_TOKEN();
|
nuclear@0
|
389 aiVector3D v;
|
nuclear@0
|
390 AI_NFF_PARSE_TRIPLE(v);
|
nuclear@0
|
391 tempPositions.push_back(v);
|
nuclear@0
|
392
|
nuclear@0
|
393 // parse all other attributes in the line
|
nuclear@0
|
394 while (true)
|
nuclear@0
|
395 {
|
nuclear@0
|
396 SkipSpaces(&sz);
|
nuclear@0
|
397 if (IsLineEnd(*sz))break;
|
nuclear@0
|
398
|
nuclear@0
|
399 // color definition
|
nuclear@0
|
400 if (TokenMatch(sz,"0x",2))
|
nuclear@0
|
401 {
|
nuclear@0
|
402 hasColor = true;
|
nuclear@0
|
403 register unsigned int numIdx = ::strtoul16(sz,&sz);
|
nuclear@0
|
404 aiColor4D clr;
|
nuclear@0
|
405 clr.a = 1.f;
|
nuclear@0
|
406
|
nuclear@0
|
407 // 0xRRGGBB
|
nuclear@0
|
408 clr.r = ((numIdx >> 16u) & 0xff) / 255.f;
|
nuclear@0
|
409 clr.g = ((numIdx >> 8u) & 0xff) / 255.f;
|
nuclear@0
|
410 clr.b = ((numIdx) & 0xff) / 255.f;
|
nuclear@0
|
411 tempColors.push_back(clr);
|
nuclear@0
|
412 }
|
nuclear@0
|
413 // normal vector
|
nuclear@0
|
414 else if (TokenMatch(sz,"norm",4))
|
nuclear@0
|
415 {
|
nuclear@0
|
416 hasNormals = true;
|
nuclear@0
|
417 AI_NFF_PARSE_TRIPLE(v);
|
nuclear@0
|
418 tempNormals.push_back(v);
|
nuclear@0
|
419 }
|
nuclear@0
|
420 // UV coordinate
|
nuclear@0
|
421 else if (TokenMatch(sz,"uv",2))
|
nuclear@0
|
422 {
|
nuclear@0
|
423 hasUVs = true;
|
nuclear@0
|
424 AI_NFF_PARSE_FLOAT(v.x);
|
nuclear@0
|
425 AI_NFF_PARSE_FLOAT(v.y);
|
nuclear@0
|
426 v.z = 0.f;
|
nuclear@0
|
427 tempTextureCoords.push_back(v);
|
nuclear@0
|
428 }
|
nuclear@0
|
429 }
|
nuclear@0
|
430
|
nuclear@0
|
431 // fill in dummies for all attributes that have not been set
|
nuclear@0
|
432 if (tempNormals.size() != tempPositions.size())
|
nuclear@0
|
433 tempNormals.push_back(vQNAN);
|
nuclear@0
|
434
|
nuclear@0
|
435 if (tempTextureCoords.size() != tempPositions.size())
|
nuclear@0
|
436 tempTextureCoords.push_back(vQNAN);
|
nuclear@0
|
437
|
nuclear@0
|
438 if (tempColors.size() != tempPositions.size())
|
nuclear@0
|
439 tempColors.push_back(cQNAN);
|
nuclear@0
|
440 }
|
nuclear@0
|
441
|
nuclear@0
|
442 AI_NFF2_GET_NEXT_TOKEN();
|
nuclear@0
|
443 if (!num)throw DeadlyImportError("NFF2: There are zero vertices");
|
nuclear@0
|
444 num = ::strtoul10(sz,&sz);
|
nuclear@0
|
445
|
nuclear@0
|
446 std::vector<unsigned int> tempIdx;
|
nuclear@0
|
447 tempIdx.reserve(10);
|
nuclear@0
|
448 for (unsigned int i = 0; i < num; ++i)
|
nuclear@0
|
449 {
|
nuclear@0
|
450 AI_NFF2_GET_NEXT_TOKEN();
|
nuclear@0
|
451 SkipSpaces(line,&sz);
|
nuclear@0
|
452 unsigned int numIdx = ::strtoul10(sz,&sz);
|
nuclear@0
|
453
|
nuclear@0
|
454 // read all faces indices
|
nuclear@0
|
455 if (numIdx)
|
nuclear@0
|
456 {
|
nuclear@0
|
457 // mesh.faces.push_back(numIdx);
|
nuclear@0
|
458 // tempIdx.erase(tempIdx.begin(),tempIdx.end());
|
nuclear@0
|
459 tempIdx.resize(numIdx);
|
nuclear@0
|
460
|
nuclear@0
|
461 for (unsigned int a = 0; a < numIdx;++a)
|
nuclear@0
|
462 {
|
nuclear@0
|
463 SkipSpaces(sz,&sz);
|
nuclear@0
|
464 m = ::strtoul10(sz,&sz);
|
nuclear@0
|
465 if (m >= (unsigned int)tempPositions.size())
|
nuclear@0
|
466 {
|
nuclear@0
|
467 DefaultLogger::get()->error("NFF2: Vertex index overflow");
|
nuclear@0
|
468 m= 0;
|
nuclear@0
|
469 }
|
nuclear@0
|
470 // mesh.vertices.push_back (tempPositions[idx]);
|
nuclear@0
|
471 tempIdx[a] = m;
|
nuclear@0
|
472 }
|
nuclear@0
|
473 }
|
nuclear@0
|
474
|
nuclear@0
|
475 // build a temporary shader object for the face.
|
nuclear@0
|
476 ShadingInfo shader;
|
nuclear@0
|
477 unsigned int matIdx = 0;
|
nuclear@0
|
478
|
nuclear@0
|
479 // white material color - we have vertex colors
|
nuclear@0
|
480 shader.color = aiColor3D(1.f,1.f,1.f);
|
nuclear@0
|
481 aiColor4D c = aiColor4D(1.f,1.f,1.f,1.f);
|
nuclear@0
|
482 while (true)
|
nuclear@0
|
483 {
|
nuclear@0
|
484 SkipSpaces(sz,&sz);
|
nuclear@0
|
485 if(IsLineEnd(*sz))break;
|
nuclear@0
|
486
|
nuclear@0
|
487 // per-polygon colors
|
nuclear@0
|
488 if (TokenMatch(sz,"0x",2))
|
nuclear@0
|
489 {
|
nuclear@0
|
490 hasColor = true;
|
nuclear@0
|
491 const char* sz2 = sz;
|
nuclear@0
|
492 numIdx = ::strtoul16(sz,&sz);
|
nuclear@0
|
493 const unsigned int diff = (unsigned int)(sz-sz2);
|
nuclear@0
|
494
|
nuclear@0
|
495 // 0xRRGGBB
|
nuclear@0
|
496 if (diff > 3)
|
nuclear@0
|
497 {
|
nuclear@0
|
498 c.r = ((numIdx >> 16u) & 0xff) / 255.f;
|
nuclear@0
|
499 c.g = ((numIdx >> 8u) & 0xff) / 255.f;
|
nuclear@0
|
500 c.b = ((numIdx) & 0xff) / 255.f;
|
nuclear@0
|
501 }
|
nuclear@0
|
502 // 0xRGB
|
nuclear@0
|
503 else
|
nuclear@0
|
504 {
|
nuclear@0
|
505 c.r = ((numIdx >> 8u) & 0xf) / 16.f;
|
nuclear@0
|
506 c.g = ((numIdx >> 4u) & 0xf) / 16.f;
|
nuclear@0
|
507 c.b = ((numIdx) & 0xf) / 16.f;
|
nuclear@0
|
508 }
|
nuclear@0
|
509 }
|
nuclear@0
|
510 // TODO - implement texture mapping here
|
nuclear@0
|
511 #if 0
|
nuclear@0
|
512 // mirror vertex texture coordinate?
|
nuclear@0
|
513 else if (TokenMatch(sz,"mirror",6))
|
nuclear@0
|
514 {
|
nuclear@0
|
515 }
|
nuclear@0
|
516 // texture coordinate scaling
|
nuclear@0
|
517 else if (TokenMatch(sz,"scale",5))
|
nuclear@0
|
518 {
|
nuclear@0
|
519 }
|
nuclear@0
|
520 // texture coordinate translation
|
nuclear@0
|
521 else if (TokenMatch(sz,"trans",5))
|
nuclear@0
|
522 {
|
nuclear@0
|
523 }
|
nuclear@0
|
524 // texture coordinate rotation angle
|
nuclear@0
|
525 else if (TokenMatch(sz,"rot",3))
|
nuclear@0
|
526 {
|
nuclear@0
|
527 }
|
nuclear@0
|
528 #endif
|
nuclear@0
|
529
|
nuclear@0
|
530 // texture file name for this polygon + mapping information
|
nuclear@0
|
531 else if ('_' == sz[0])
|
nuclear@0
|
532 {
|
nuclear@0
|
533 // get mapping information
|
nuclear@0
|
534 switch (sz[1])
|
nuclear@0
|
535 {
|
nuclear@0
|
536 case 'v':
|
nuclear@0
|
537 case 'V':
|
nuclear@0
|
538
|
nuclear@0
|
539 shader.shaded = false;
|
nuclear@0
|
540 break;
|
nuclear@0
|
541
|
nuclear@0
|
542 case 't':
|
nuclear@0
|
543 case 'T':
|
nuclear@0
|
544 case 'u':
|
nuclear@0
|
545 case 'U':
|
nuclear@0
|
546
|
nuclear@0
|
547 DefaultLogger::get()->warn("Unsupported NFF2 texture attribute: trans");
|
nuclear@0
|
548 };
|
nuclear@0
|
549 if (!sz[1] || '_' != sz[2])
|
nuclear@0
|
550 {
|
nuclear@0
|
551 DefaultLogger::get()->warn("NFF2: Expected underscore after texture attributes");
|
nuclear@0
|
552 continue;
|
nuclear@0
|
553 }
|
nuclear@0
|
554 const char* sz2 = sz+3;
|
nuclear@0
|
555 while (!IsSpaceOrNewLine( *sz ))++sz;
|
nuclear@0
|
556 const unsigned int diff = (unsigned int)(sz-sz2);
|
nuclear@0
|
557 if (diff)shader.texFile = std::string(sz2,diff);
|
nuclear@0
|
558 }
|
nuclear@0
|
559
|
nuclear@0
|
560 // Two-sided material?
|
nuclear@0
|
561 else if (TokenMatch(sz,"both",4))
|
nuclear@0
|
562 {
|
nuclear@0
|
563 shader.twoSided = true;
|
nuclear@0
|
564 }
|
nuclear@0
|
565
|
nuclear@0
|
566 // Material ID?
|
nuclear@0
|
567 else if (!materialTable.empty() && TokenMatch(sz,"matid",5))
|
nuclear@0
|
568 {
|
nuclear@0
|
569 SkipSpaces(&sz);
|
nuclear@0
|
570 matIdx = ::strtoul10(sz,&sz);
|
nuclear@0
|
571 if (matIdx >= materialTable.size())
|
nuclear@0
|
572 {
|
nuclear@0
|
573 DefaultLogger::get()->error("NFF2: Material index overflow.");
|
nuclear@0
|
574 matIdx = 0;
|
nuclear@0
|
575 }
|
nuclear@0
|
576
|
nuclear@0
|
577 // now combine our current shader with the shader we
|
nuclear@0
|
578 // read from the material table.
|
nuclear@0
|
579 ShadingInfo& mat = materialTable[matIdx];
|
nuclear@0
|
580 shader.ambient = mat.ambient;
|
nuclear@0
|
581 shader.diffuse = mat.diffuse;
|
nuclear@0
|
582 shader.emissive = mat.emissive;
|
nuclear@0
|
583 shader.opacity = mat.opacity;
|
nuclear@0
|
584 shader.specular = mat.specular;
|
nuclear@0
|
585 shader.shininess = mat.shininess;
|
nuclear@0
|
586 }
|
nuclear@0
|
587 else SkipToken(sz);
|
nuclear@0
|
588 }
|
nuclear@0
|
589
|
nuclear@0
|
590 // search the list of all shaders we have for this object whether
|
nuclear@0
|
591 // there is an identical one. In this case, we append our mesh
|
nuclear@0
|
592 // data to it.
|
nuclear@0
|
593 MeshInfo* mesh = NULL;
|
nuclear@0
|
594 for (std::vector<MeshInfo>::iterator it = meshes.begin() + objStart, end = meshes.end();
|
nuclear@0
|
595 it != end; ++it)
|
nuclear@0
|
596 {
|
nuclear@0
|
597 if ((*it).shader == shader && (*it).matIndex == matIdx)
|
nuclear@0
|
598 {
|
nuclear@0
|
599 // we have one, we can append our data to it
|
nuclear@0
|
600 mesh = &(*it);
|
nuclear@0
|
601 }
|
nuclear@0
|
602 }
|
nuclear@0
|
603 if (!mesh)
|
nuclear@0
|
604 {
|
nuclear@0
|
605 meshes.push_back(MeshInfo(PatchType_Simple,false));
|
nuclear@0
|
606 mesh = &meshes.back();
|
nuclear@0
|
607 mesh->matIndex = matIdx;
|
nuclear@0
|
608
|
nuclear@0
|
609 // We need to add a new mesh to the list. We assign
|
nuclear@0
|
610 // an unique name to it to make sure the scene will
|
nuclear@0
|
611 // pass the validation step for the moment.
|
nuclear@0
|
612 // TODO: fix naming of objects in the scenegraph later
|
nuclear@0
|
613 if (objectName.length())
|
nuclear@0
|
614 {
|
nuclear@0
|
615 ::strcpy(mesh->name,objectName.c_str());
|
nuclear@0
|
616 ASSIMP_itoa10(&mesh->name[objectName.length()],30,subMeshIdx++);
|
nuclear@0
|
617 }
|
nuclear@0
|
618
|
nuclear@0
|
619 // copy the shader to the mesh.
|
nuclear@0
|
620 mesh->shader = shader;
|
nuclear@0
|
621 }
|
nuclear@0
|
622
|
nuclear@0
|
623 // fill the mesh with data
|
nuclear@0
|
624 if (!tempIdx.empty())
|
nuclear@0
|
625 {
|
nuclear@0
|
626 mesh->faces.push_back((unsigned int)tempIdx.size());
|
nuclear@0
|
627 for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
|
nuclear@0
|
628 it != end;++it)
|
nuclear@0
|
629 {
|
nuclear@0
|
630 m = *it;
|
nuclear@0
|
631
|
nuclear@0
|
632 // copy colors -vertex color specifications override polygon color specifications
|
nuclear@0
|
633 if (hasColor)
|
nuclear@0
|
634 {
|
nuclear@0
|
635 const aiColor4D& clr = tempColors[m];
|
nuclear@0
|
636 mesh->colors.push_back((is_qnan( clr.r ) ? c : clr));
|
nuclear@0
|
637 }
|
nuclear@0
|
638
|
nuclear@0
|
639 // positions should always be there
|
nuclear@0
|
640 mesh->vertices.push_back (tempPositions[m]);
|
nuclear@0
|
641
|
nuclear@0
|
642 // copy normal vectors
|
nuclear@0
|
643 if (hasNormals)
|
nuclear@0
|
644 mesh->normals.push_back (tempNormals[m]);
|
nuclear@0
|
645
|
nuclear@0
|
646 // copy texture coordinates
|
nuclear@0
|
647 if (hasUVs)
|
nuclear@0
|
648 mesh->uvs.push_back (tempTextureCoords[m]);
|
nuclear@0
|
649 }
|
nuclear@0
|
650 }
|
nuclear@0
|
651 }
|
nuclear@0
|
652 if (!num)throw DeadlyImportError("NFF2: There are zero faces");
|
nuclear@0
|
653 }
|
nuclear@0
|
654 }
|
nuclear@0
|
655 camLookAt = camLookAt + camPos;
|
nuclear@0
|
656 }
|
nuclear@0
|
657 else // "Normal" Neutral file format that is quite more common
|
nuclear@0
|
658 {
|
nuclear@0
|
659 while (GetNextLine(buffer,line))
|
nuclear@0
|
660 {
|
nuclear@0
|
661 sz = line;
|
nuclear@0
|
662 if ('p' == line[0] || TokenMatch(sz,"tpp",3))
|
nuclear@0
|
663 {
|
nuclear@0
|
664 MeshInfo* out = NULL;
|
nuclear@0
|
665
|
nuclear@0
|
666 // 'tpp' - texture polygon patch primitive
|
nuclear@0
|
667 if ('t' == line[0])
|
nuclear@0
|
668 {
|
nuclear@0
|
669 currentMeshWithUVCoords = NULL;
|
nuclear@0
|
670 for (std::vector<MeshInfo>::iterator it = meshesWithUVCoords.begin(), end = meshesWithUVCoords.end();
|
nuclear@0
|
671 it != end;++it)
|
nuclear@0
|
672 {
|
nuclear@0
|
673 if ((*it).shader == s)
|
nuclear@0
|
674 {
|
nuclear@0
|
675 currentMeshWithUVCoords = &(*it);
|
nuclear@0
|
676 break;
|
nuclear@0
|
677 }
|
nuclear@0
|
678 }
|
nuclear@0
|
679
|
nuclear@0
|
680 if (!currentMeshWithUVCoords)
|
nuclear@0
|
681 {
|
nuclear@0
|
682 meshesWithUVCoords.push_back(MeshInfo(PatchType_UVAndNormals));
|
nuclear@0
|
683 currentMeshWithUVCoords = &meshesWithUVCoords.back();
|
nuclear@0
|
684 currentMeshWithUVCoords->shader = s;
|
nuclear@0
|
685 }
|
nuclear@0
|
686 out = currentMeshWithUVCoords;
|
nuclear@0
|
687 }
|
nuclear@0
|
688 // 'pp' - polygon patch primitive
|
nuclear@0
|
689 else if ('p' == line[1])
|
nuclear@0
|
690 {
|
nuclear@0
|
691 currentMeshWithNormals = NULL;
|
nuclear@0
|
692 for (std::vector<MeshInfo>::iterator it = meshesWithNormals.begin(), end = meshesWithNormals.end();
|
nuclear@0
|
693 it != end;++it)
|
nuclear@0
|
694 {
|
nuclear@0
|
695 if ((*it).shader == s)
|
nuclear@0
|
696 {
|
nuclear@0
|
697 currentMeshWithNormals = &(*it);
|
nuclear@0
|
698 break;
|
nuclear@0
|
699 }
|
nuclear@0
|
700 }
|
nuclear@0
|
701
|
nuclear@0
|
702 if (!currentMeshWithNormals)
|
nuclear@0
|
703 {
|
nuclear@0
|
704 meshesWithNormals.push_back(MeshInfo(PatchType_Normals));
|
nuclear@0
|
705 currentMeshWithNormals = &meshesWithNormals.back();
|
nuclear@0
|
706 currentMeshWithNormals->shader = s;
|
nuclear@0
|
707 }
|
nuclear@0
|
708 sz = &line[2];out = currentMeshWithNormals;
|
nuclear@0
|
709 }
|
nuclear@0
|
710 // 'p' - polygon primitive
|
nuclear@0
|
711 else
|
nuclear@0
|
712 {
|
nuclear@0
|
713 currentMesh = NULL;
|
nuclear@0
|
714 for (std::vector<MeshInfo>::iterator it = meshes.begin(), end = meshes.end();
|
nuclear@0
|
715 it != end;++it)
|
nuclear@0
|
716 {
|
nuclear@0
|
717 if ((*it).shader == s)
|
nuclear@0
|
718 {
|
nuclear@0
|
719 currentMesh = &(*it);
|
nuclear@0
|
720 break;
|
nuclear@0
|
721 }
|
nuclear@0
|
722 }
|
nuclear@0
|
723
|
nuclear@0
|
724 if (!currentMesh)
|
nuclear@0
|
725 {
|
nuclear@0
|
726 meshes.push_back(MeshInfo(PatchType_Simple));
|
nuclear@0
|
727 currentMesh = &meshes.back();
|
nuclear@0
|
728 currentMesh->shader = s;
|
nuclear@0
|
729 }
|
nuclear@0
|
730 sz = &line[1];out = currentMesh;
|
nuclear@0
|
731 }
|
nuclear@0
|
732 SkipSpaces(sz,&sz);
|
nuclear@0
|
733 m = strtoul10(sz);
|
nuclear@0
|
734
|
nuclear@0
|
735 // ---- flip the face order
|
nuclear@0
|
736 out->vertices.resize(out->vertices.size()+m);
|
nuclear@0
|
737 if (out != currentMesh)
|
nuclear@0
|
738 {
|
nuclear@0
|
739 out->normals.resize(out->vertices.size());
|
nuclear@0
|
740 }
|
nuclear@0
|
741 if (out == currentMeshWithUVCoords)
|
nuclear@0
|
742 {
|
nuclear@0
|
743 out->uvs.resize(out->vertices.size());
|
nuclear@0
|
744 }
|
nuclear@0
|
745 for (unsigned int n = 0; n < m;++n)
|
nuclear@0
|
746 {
|
nuclear@0
|
747 if(!GetNextLine(buffer,line))
|
nuclear@0
|
748 {
|
nuclear@0
|
749 DefaultLogger::get()->error("NFF: Unexpected EOF was encountered. Patch definition incomplete");
|
nuclear@0
|
750 continue;
|
nuclear@0
|
751 }
|
nuclear@0
|
752
|
nuclear@0
|
753 aiVector3D v; sz = &line[0];
|
nuclear@0
|
754 AI_NFF_PARSE_TRIPLE(v);
|
nuclear@0
|
755 out->vertices[out->vertices.size()-n-1] = v;
|
nuclear@0
|
756
|
nuclear@0
|
757 if (out != currentMesh)
|
nuclear@0
|
758 {
|
nuclear@0
|
759 AI_NFF_PARSE_TRIPLE(v);
|
nuclear@0
|
760 out->normals[out->vertices.size()-n-1] = v;
|
nuclear@0
|
761 }
|
nuclear@0
|
762 if (out == currentMeshWithUVCoords)
|
nuclear@0
|
763 {
|
nuclear@0
|
764 // FIX: in one test file this wraps over multiple lines
|
nuclear@0
|
765 SkipSpaces(&sz);
|
nuclear@0
|
766 if (IsLineEnd(*sz))
|
nuclear@0
|
767 {
|
nuclear@0
|
768 GetNextLine(buffer,line);
|
nuclear@0
|
769 sz = line;
|
nuclear@0
|
770 }
|
nuclear@0
|
771 AI_NFF_PARSE_FLOAT(v.x);
|
nuclear@0
|
772 SkipSpaces(&sz);
|
nuclear@0
|
773 if (IsLineEnd(*sz))
|
nuclear@0
|
774 {
|
nuclear@0
|
775 GetNextLine(buffer,line);
|
nuclear@0
|
776 sz = line;
|
nuclear@0
|
777 }
|
nuclear@0
|
778 AI_NFF_PARSE_FLOAT(v.y);
|
nuclear@0
|
779 v.y = 1.f - v.y;
|
nuclear@0
|
780 out->uvs[out->vertices.size()-n-1] = v;
|
nuclear@0
|
781 }
|
nuclear@0
|
782 }
|
nuclear@0
|
783 out->faces.push_back(m);
|
nuclear@0
|
784 }
|
nuclear@0
|
785 // 'f' - shading information block
|
nuclear@0
|
786 else if (TokenMatch(sz,"f",1))
|
nuclear@0
|
787 {
|
nuclear@0
|
788 float d;
|
nuclear@0
|
789
|
nuclear@0
|
790 // read the RGB colors
|
nuclear@0
|
791 AI_NFF_PARSE_TRIPLE(s.color);
|
nuclear@0
|
792
|
nuclear@0
|
793 // read the other properties
|
nuclear@0
|
794 AI_NFF_PARSE_FLOAT(s.diffuse.r);
|
nuclear@0
|
795 AI_NFF_PARSE_FLOAT(s.specular.r);
|
nuclear@0
|
796 AI_NFF_PARSE_FLOAT(d); // skip shininess and transmittance
|
nuclear@0
|
797 AI_NFF_PARSE_FLOAT(d);
|
nuclear@0
|
798 AI_NFF_PARSE_FLOAT(s.refracti);
|
nuclear@0
|
799
|
nuclear@0
|
800 // NFF2 uses full colors here so we need to use them too
|
nuclear@0
|
801 // although NFF uses simple scaling factors
|
nuclear@0
|
802 s.diffuse.g = s.diffuse.b = s.diffuse.r;
|
nuclear@0
|
803 s.specular.g = s.specular.b = s.specular.r;
|
nuclear@0
|
804
|
nuclear@0
|
805 // if the next one is NOT a number we assume it is a texture file name
|
nuclear@0
|
806 // this feature is used by some NFF files on the internet and it has
|
nuclear@0
|
807 // been implemented as it can be really useful
|
nuclear@0
|
808 SkipSpaces(&sz);
|
nuclear@0
|
809 if (!IsNumeric(*sz))
|
nuclear@0
|
810 {
|
nuclear@0
|
811 // TODO: Support full file names with spaces and quotation marks ...
|
nuclear@0
|
812 const char* p = sz;
|
nuclear@0
|
813 while (!IsSpaceOrNewLine( *sz ))++sz;
|
nuclear@0
|
814
|
nuclear@0
|
815 unsigned int diff = (unsigned int)(sz-p);
|
nuclear@0
|
816 if (diff)
|
nuclear@0
|
817 {
|
nuclear@0
|
818 s.texFile = std::string(p,diff);
|
nuclear@0
|
819 }
|
nuclear@0
|
820 }
|
nuclear@0
|
821 else
|
nuclear@0
|
822 {
|
nuclear@0
|
823 AI_NFF_PARSE_FLOAT(s.ambient); // optional
|
nuclear@0
|
824 }
|
nuclear@0
|
825 }
|
nuclear@0
|
826 // 'shader' - other way to specify a texture
|
nuclear@0
|
827 else if (TokenMatch(sz,"shader",6))
|
nuclear@0
|
828 {
|
nuclear@0
|
829 SkipSpaces(&sz);
|
nuclear@0
|
830 const char* old = sz;
|
nuclear@0
|
831 while (!IsSpaceOrNewLine(*sz))++sz;
|
nuclear@0
|
832 s.texFile = std::string(old, (uintptr_t)sz - (uintptr_t)old);
|
nuclear@0
|
833 }
|
nuclear@0
|
834 // 'l' - light source
|
nuclear@0
|
835 else if (TokenMatch(sz,"l",1))
|
nuclear@0
|
836 {
|
nuclear@0
|
837 lights.push_back(Light());
|
nuclear@0
|
838 Light& light = lights.back();
|
nuclear@0
|
839
|
nuclear@0
|
840 AI_NFF_PARSE_TRIPLE(light.position);
|
nuclear@0
|
841 AI_NFF_PARSE_FLOAT (light.intensity);
|
nuclear@0
|
842 AI_NFF_PARSE_TRIPLE(light.color);
|
nuclear@0
|
843 }
|
nuclear@0
|
844 // 's' - sphere
|
nuclear@0
|
845 else if (TokenMatch(sz,"s",1))
|
nuclear@0
|
846 {
|
nuclear@0
|
847 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
848 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
849 currentMesh.shader = s;
|
nuclear@0
|
850 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
|
nuclear@0
|
851
|
nuclear@0
|
852 AI_NFF_PARSE_SHAPE_INFORMATION();
|
nuclear@0
|
853
|
nuclear@0
|
854 // we don't need scaling or translation here - we do it in the node's transform
|
nuclear@0
|
855 StandardShapes::MakeSphere(iTesselation, currentMesh.vertices);
|
nuclear@0
|
856 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
857
|
nuclear@0
|
858 // generate a name for the mesh
|
nuclear@0
|
859 ::sprintf(currentMesh.name,"sphere_%i",sphere++);
|
nuclear@0
|
860 }
|
nuclear@0
|
861 // 'dod' - dodecahedron
|
nuclear@0
|
862 else if (TokenMatch(sz,"dod",3))
|
nuclear@0
|
863 {
|
nuclear@0
|
864 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
865 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
866 currentMesh.shader = s;
|
nuclear@0
|
867 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
|
nuclear@0
|
868
|
nuclear@0
|
869 AI_NFF_PARSE_SHAPE_INFORMATION();
|
nuclear@0
|
870
|
nuclear@0
|
871 // we don't need scaling or translation here - we do it in the node's transform
|
nuclear@0
|
872 StandardShapes::MakeDodecahedron(currentMesh.vertices);
|
nuclear@0
|
873 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
874
|
nuclear@0
|
875 // generate a name for the mesh
|
nuclear@0
|
876 ::sprintf(currentMesh.name,"dodecahedron_%i",dodecahedron++);
|
nuclear@0
|
877 }
|
nuclear@0
|
878
|
nuclear@0
|
879 // 'oct' - octahedron
|
nuclear@0
|
880 else if (TokenMatch(sz,"oct",3))
|
nuclear@0
|
881 {
|
nuclear@0
|
882 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
883 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
884 currentMesh.shader = s;
|
nuclear@0
|
885 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
|
nuclear@0
|
886
|
nuclear@0
|
887 AI_NFF_PARSE_SHAPE_INFORMATION();
|
nuclear@0
|
888
|
nuclear@0
|
889 // we don't need scaling or translation here - we do it in the node's transform
|
nuclear@0
|
890 StandardShapes::MakeOctahedron(currentMesh.vertices);
|
nuclear@0
|
891 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
892
|
nuclear@0
|
893 // generate a name for the mesh
|
nuclear@0
|
894 ::sprintf(currentMesh.name,"octahedron_%i",octahedron++);
|
nuclear@0
|
895 }
|
nuclear@0
|
896
|
nuclear@0
|
897 // 'tet' - tetrahedron
|
nuclear@0
|
898 else if (TokenMatch(sz,"tet",3))
|
nuclear@0
|
899 {
|
nuclear@0
|
900 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
901 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
902 currentMesh.shader = s;
|
nuclear@0
|
903 currentMesh.shader.mapping = aiTextureMapping_SPHERE;
|
nuclear@0
|
904
|
nuclear@0
|
905 AI_NFF_PARSE_SHAPE_INFORMATION();
|
nuclear@0
|
906
|
nuclear@0
|
907 // we don't need scaling or translation here - we do it in the node's transform
|
nuclear@0
|
908 StandardShapes::MakeTetrahedron(currentMesh.vertices);
|
nuclear@0
|
909 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
910
|
nuclear@0
|
911 // generate a name for the mesh
|
nuclear@0
|
912 ::sprintf(currentMesh.name,"tetrahedron_%i",tetrahedron++);
|
nuclear@0
|
913 }
|
nuclear@0
|
914
|
nuclear@0
|
915 // 'hex' - hexahedron
|
nuclear@0
|
916 else if (TokenMatch(sz,"hex",3))
|
nuclear@0
|
917 {
|
nuclear@0
|
918 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
919 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
920 currentMesh.shader = s;
|
nuclear@0
|
921 currentMesh.shader.mapping = aiTextureMapping_BOX;
|
nuclear@0
|
922
|
nuclear@0
|
923 AI_NFF_PARSE_SHAPE_INFORMATION();
|
nuclear@0
|
924
|
nuclear@0
|
925 // we don't need scaling or translation here - we do it in the node's transform
|
nuclear@0
|
926 StandardShapes::MakeHexahedron(currentMesh.vertices);
|
nuclear@0
|
927 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
928
|
nuclear@0
|
929 // generate a name for the mesh
|
nuclear@0
|
930 ::sprintf(currentMesh.name,"hexahedron_%i",hexahedron++);
|
nuclear@0
|
931 }
|
nuclear@0
|
932 // 'c' - cone
|
nuclear@0
|
933 else if (TokenMatch(sz,"c",1))
|
nuclear@0
|
934 {
|
nuclear@0
|
935 meshesLocked.push_back(MeshInfo(PatchType_Simple,true));
|
nuclear@0
|
936 MeshInfo& currentMesh = meshesLocked.back();
|
nuclear@0
|
937 currentMesh.shader = s;
|
nuclear@0
|
938 currentMesh.shader.mapping = aiTextureMapping_CYLINDER;
|
nuclear@0
|
939
|
nuclear@0
|
940 if(!GetNextLine(buffer,line))
|
nuclear@0
|
941 {
|
nuclear@0
|
942 DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
|
nuclear@0
|
943 break;
|
nuclear@0
|
944 }
|
nuclear@0
|
945 sz = line;
|
nuclear@0
|
946
|
nuclear@0
|
947 // read the two center points and the respective radii
|
nuclear@0
|
948 aiVector3D center1, center2; float radius1, radius2;
|
nuclear@0
|
949 AI_NFF_PARSE_TRIPLE(center1);
|
nuclear@0
|
950 AI_NFF_PARSE_FLOAT(radius1);
|
nuclear@0
|
951
|
nuclear@0
|
952 if(!GetNextLine(buffer,line))
|
nuclear@0
|
953 {
|
nuclear@0
|
954 DefaultLogger::get()->error("NFF: Unexpected end of file (cone definition not complete)");
|
nuclear@0
|
955 break;
|
nuclear@0
|
956 }
|
nuclear@0
|
957 sz = line;
|
nuclear@0
|
958
|
nuclear@0
|
959 AI_NFF_PARSE_TRIPLE(center2);
|
nuclear@0
|
960 AI_NFF_PARSE_FLOAT(radius2);
|
nuclear@0
|
961
|
nuclear@0
|
962 // compute the center point of the cone/cylinder -
|
nuclear@0
|
963 // it is its local transformation origin
|
nuclear@0
|
964 currentMesh.dir = center2-center1;
|
nuclear@0
|
965 currentMesh.center = center1+currentMesh.dir/2.f;
|
nuclear@0
|
966
|
nuclear@0
|
967 float f;
|
nuclear@0
|
968 if (( f = currentMesh.dir.Length()) < 10e-3f )
|
nuclear@0
|
969 {
|
nuclear@0
|
970 DefaultLogger::get()->error("NFF: Cone height is close to zero");
|
nuclear@0
|
971 continue;
|
nuclear@0
|
972 }
|
nuclear@0
|
973 currentMesh.dir /= f; // normalize
|
nuclear@0
|
974
|
nuclear@0
|
975 // generate the cone - it consists of simple triangles
|
nuclear@0
|
976 StandardShapes::MakeCone(f, radius1, radius2,
|
nuclear@0
|
977 integer_pow(4, iTesselation), currentMesh.vertices);
|
nuclear@0
|
978
|
nuclear@0
|
979 // MakeCone() returns tris
|
nuclear@0
|
980 currentMesh.faces.resize(currentMesh.vertices.size()/3,3);
|
nuclear@0
|
981
|
nuclear@0
|
982 // generate a name for the mesh. 'cone' if it a cone,
|
nuclear@0
|
983 // 'cylinder' if it is a cylinder. Funny, isn't it?
|
nuclear@0
|
984 if (radius1 != radius2)
|
nuclear@0
|
985 ::sprintf(currentMesh.name,"cone_%i",cone++);
|
nuclear@0
|
986 else ::sprintf(currentMesh.name,"cylinder_%i",cylinder++);
|
nuclear@0
|
987 }
|
nuclear@0
|
988 // 'tess' - tesselation
|
nuclear@0
|
989 else if (TokenMatch(sz,"tess",4))
|
nuclear@0
|
990 {
|
nuclear@0
|
991 SkipSpaces(&sz);
|
nuclear@0
|
992 iTesselation = strtoul10(sz);
|
nuclear@0
|
993 }
|
nuclear@0
|
994 // 'from' - camera position
|
nuclear@0
|
995 else if (TokenMatch(sz,"from",4))
|
nuclear@0
|
996 {
|
nuclear@0
|
997 AI_NFF_PARSE_TRIPLE(camPos);
|
nuclear@0
|
998 hasCam = true;
|
nuclear@0
|
999 }
|
nuclear@0
|
1000 // 'at' - camera look-at vector
|
nuclear@0
|
1001 else if (TokenMatch(sz,"at",2))
|
nuclear@0
|
1002 {
|
nuclear@0
|
1003 AI_NFF_PARSE_TRIPLE(camLookAt);
|
nuclear@0
|
1004 hasCam = true;
|
nuclear@0
|
1005 }
|
nuclear@0
|
1006 // 'up' - camera up vector
|
nuclear@0
|
1007 else if (TokenMatch(sz,"up",2))
|
nuclear@0
|
1008 {
|
nuclear@0
|
1009 AI_NFF_PARSE_TRIPLE(camUp);
|
nuclear@0
|
1010 hasCam = true;
|
nuclear@0
|
1011 }
|
nuclear@0
|
1012 // 'angle' - (half?) camera field of view
|
nuclear@0
|
1013 else if (TokenMatch(sz,"angle",5))
|
nuclear@0
|
1014 {
|
nuclear@0
|
1015 AI_NFF_PARSE_FLOAT(angle);
|
nuclear@0
|
1016 hasCam = true;
|
nuclear@0
|
1017 }
|
nuclear@0
|
1018 // 'resolution' - used to compute the screen aspect
|
nuclear@0
|
1019 else if (TokenMatch(sz,"resolution",10))
|
nuclear@0
|
1020 {
|
nuclear@0
|
1021 AI_NFF_PARSE_FLOAT(resolution.x);
|
nuclear@0
|
1022 AI_NFF_PARSE_FLOAT(resolution.y);
|
nuclear@0
|
1023 hasCam = true;
|
nuclear@0
|
1024 }
|
nuclear@0
|
1025 // 'pb' - bezier patch. Not supported yet
|
nuclear@0
|
1026 else if (TokenMatch(sz,"pb",2))
|
nuclear@0
|
1027 {
|
nuclear@0
|
1028 DefaultLogger::get()->error("NFF: Encountered unsupported ID: bezier patch");
|
nuclear@0
|
1029 }
|
nuclear@0
|
1030 // 'pn' - NURBS. Not supported yet
|
nuclear@0
|
1031 else if (TokenMatch(sz,"pn",2) || TokenMatch(sz,"pnn",3))
|
nuclear@0
|
1032 {
|
nuclear@0
|
1033 DefaultLogger::get()->error("NFF: Encountered unsupported ID: NURBS");
|
nuclear@0
|
1034 }
|
nuclear@0
|
1035 // '' - comment
|
nuclear@0
|
1036 else if ('#' == line[0])
|
nuclear@0
|
1037 {
|
nuclear@0
|
1038 const char* sz;SkipSpaces(&line[1],&sz);
|
nuclear@0
|
1039 if (!IsLineEnd(*sz))DefaultLogger::get()->info(sz);
|
nuclear@0
|
1040 }
|
nuclear@0
|
1041 }
|
nuclear@0
|
1042 }
|
nuclear@0
|
1043
|
nuclear@0
|
1044 // copy all arrays into one large
|
nuclear@0
|
1045 meshes.reserve (meshes.size()+meshesLocked.size()+meshesWithNormals.size()+meshesWithUVCoords.size());
|
nuclear@0
|
1046 meshes.insert (meshes.end(),meshesLocked.begin(),meshesLocked.end());
|
nuclear@0
|
1047 meshes.insert (meshes.end(),meshesWithNormals.begin(),meshesWithNormals.end());
|
nuclear@0
|
1048 meshes.insert (meshes.end(),meshesWithUVCoords.begin(),meshesWithUVCoords.end());
|
nuclear@0
|
1049
|
nuclear@0
|
1050 // now generate output meshes. first find out how many meshes we'll need
|
nuclear@0
|
1051 std::vector<MeshInfo>::const_iterator it = meshes.begin(), end = meshes.end();
|
nuclear@0
|
1052 for (;it != end;++it)
|
nuclear@0
|
1053 {
|
nuclear@0
|
1054 if (!(*it).faces.empty())
|
nuclear@0
|
1055 {
|
nuclear@0
|
1056 ++pScene->mNumMeshes;
|
nuclear@0
|
1057 if ((*it).name[0])++numNamed;
|
nuclear@0
|
1058 }
|
nuclear@0
|
1059 }
|
nuclear@0
|
1060
|
nuclear@0
|
1061 // generate a dummy root node - assign all unnamed elements such
|
nuclear@0
|
1062 // as polygons and polygon patches to the root node and generate
|
nuclear@0
|
1063 // sub nodes for named objects such as spheres and cones.
|
nuclear@0
|
1064 aiNode* const root = new aiNode();
|
nuclear@0
|
1065 root->mName.Set("<NFF_Root>");
|
nuclear@0
|
1066 root->mNumChildren = numNamed + (hasCam ? 1 : 0) + (unsigned int) lights.size();
|
nuclear@0
|
1067 root->mNumMeshes = pScene->mNumMeshes-numNamed;
|
nuclear@0
|
1068
|
nuclear@0
|
1069 aiNode** ppcChildren = NULL;
|
nuclear@0
|
1070 unsigned int* pMeshes = NULL;
|
nuclear@0
|
1071 if (root->mNumMeshes)
|
nuclear@0
|
1072 pMeshes = root->mMeshes = new unsigned int[root->mNumMeshes];
|
nuclear@0
|
1073 if (root->mNumChildren)
|
nuclear@0
|
1074 ppcChildren = root->mChildren = new aiNode*[root->mNumChildren];
|
nuclear@0
|
1075
|
nuclear@0
|
1076 // generate the camera
|
nuclear@0
|
1077 if (hasCam)
|
nuclear@0
|
1078 {
|
nuclear@0
|
1079 aiNode* nd = *ppcChildren = new aiNode();
|
nuclear@0
|
1080 nd->mName.Set("<NFF_Camera>");
|
nuclear@0
|
1081 nd->mParent = root;
|
nuclear@0
|
1082
|
nuclear@0
|
1083 // allocate the camera in the scene
|
nuclear@0
|
1084 pScene->mNumCameras = 1;
|
nuclear@0
|
1085 pScene->mCameras = new aiCamera*[1];
|
nuclear@0
|
1086 aiCamera* c = pScene->mCameras[0] = new aiCamera;
|
nuclear@0
|
1087
|
nuclear@0
|
1088 c->mName = nd->mName; // make sure the names are identical
|
nuclear@0
|
1089 c->mHorizontalFOV = AI_DEG_TO_RAD( angle );
|
nuclear@0
|
1090 c->mLookAt = camLookAt - camPos;
|
nuclear@0
|
1091 c->mPosition = camPos;
|
nuclear@0
|
1092 c->mUp = camUp;
|
nuclear@0
|
1093
|
nuclear@0
|
1094 // If the resolution is not specified in the file, we
|
nuclear@0
|
1095 // need to set 1.0 as aspect.
|
nuclear@0
|
1096 c->mAspect = (!resolution.y ? 0.f : resolution.x / resolution.y);
|
nuclear@0
|
1097 ++ppcChildren;
|
nuclear@0
|
1098 }
|
nuclear@0
|
1099
|
nuclear@0
|
1100 // generate light sources
|
nuclear@0
|
1101 if (!lights.empty())
|
nuclear@0
|
1102 {
|
nuclear@0
|
1103 pScene->mNumLights = (unsigned int)lights.size();
|
nuclear@0
|
1104 pScene->mLights = new aiLight*[pScene->mNumLights];
|
nuclear@0
|
1105 for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
|
nuclear@0
|
1106 {
|
nuclear@0
|
1107 const Light& l = lights[i];
|
nuclear@0
|
1108
|
nuclear@0
|
1109 aiNode* nd = *ppcChildren = new aiNode();
|
nuclear@0
|
1110 nd->mParent = root;
|
nuclear@0
|
1111
|
nuclear@0
|
1112 nd->mName.length = ::sprintf(nd->mName.data,"<NFF_Light%i>",i);
|
nuclear@0
|
1113
|
nuclear@0
|
1114 // allocate the light in the scene data structure
|
nuclear@0
|
1115 aiLight* out = pScene->mLights[i] = new aiLight();
|
nuclear@0
|
1116 out->mName = nd->mName; // make sure the names are identical
|
nuclear@0
|
1117 out->mType = aiLightSource_POINT;
|
nuclear@0
|
1118 out->mColorDiffuse = out->mColorSpecular = l.color * l.intensity;
|
nuclear@0
|
1119 out->mPosition = l.position;
|
nuclear@0
|
1120 }
|
nuclear@0
|
1121 }
|
nuclear@0
|
1122
|
nuclear@0
|
1123 if (!pScene->mNumMeshes)throw DeadlyImportError("NFF: No meshes loaded");
|
nuclear@0
|
1124 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
nuclear@0
|
1125 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
|
nuclear@0
|
1126 for (it = meshes.begin(), m = 0; it != end;++it)
|
nuclear@0
|
1127 {
|
nuclear@0
|
1128 if ((*it).faces.empty())continue;
|
nuclear@0
|
1129
|
nuclear@0
|
1130 const MeshInfo& src = *it;
|
nuclear@0
|
1131 aiMesh* const mesh = pScene->mMeshes[m] = new aiMesh();
|
nuclear@0
|
1132 mesh->mNumVertices = (unsigned int)src.vertices.size();
|
nuclear@0
|
1133 mesh->mNumFaces = (unsigned int)src.faces.size();
|
nuclear@0
|
1134
|
nuclear@0
|
1135 // Generate sub nodes for named meshes
|
nuclear@0
|
1136 if (src.name[0])
|
nuclear@0
|
1137 {
|
nuclear@0
|
1138 aiNode* const node = *ppcChildren = new aiNode();
|
nuclear@0
|
1139 node->mParent = root;
|
nuclear@0
|
1140 node->mNumMeshes = 1;
|
nuclear@0
|
1141 node->mMeshes = new unsigned int[1];
|
nuclear@0
|
1142 node->mMeshes[0] = m;
|
nuclear@0
|
1143 node->mName.Set(src.name);
|
nuclear@0
|
1144
|
nuclear@0
|
1145 // setup the transformation matrix of the node
|
nuclear@0
|
1146 aiMatrix4x4::FromToMatrix(aiVector3D(0.f,1.f,0.f),
|
nuclear@0
|
1147 src.dir,node->mTransformation);
|
nuclear@0
|
1148
|
nuclear@0
|
1149 aiMatrix4x4& mat = node->mTransformation;
|
nuclear@0
|
1150 mat.a1 *= src.radius.x; mat.b1 *= src.radius.x; mat.c1 *= src.radius.x;
|
nuclear@0
|
1151 mat.a2 *= src.radius.y; mat.b2 *= src.radius.y; mat.c2 *= src.radius.y;
|
nuclear@0
|
1152 mat.a3 *= src.radius.z; mat.b3 *= src.radius.z; mat.c3 *= src.radius.z;
|
nuclear@0
|
1153 mat.a4 = src.center.x;
|
nuclear@0
|
1154 mat.b4 = src.center.y;
|
nuclear@0
|
1155 mat.c4 = src.center.z;
|
nuclear@0
|
1156
|
nuclear@0
|
1157 ++ppcChildren;
|
nuclear@0
|
1158 }
|
nuclear@0
|
1159 else *pMeshes++ = m;
|
nuclear@0
|
1160
|
nuclear@0
|
1161 // copy vertex positions
|
nuclear@0
|
1162 mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
1163 ::memcpy(mesh->mVertices,&src.vertices[0],
|
nuclear@0
|
1164 sizeof(aiVector3D)*mesh->mNumVertices);
|
nuclear@0
|
1165
|
nuclear@0
|
1166 // NFF2: there could be vertex colors
|
nuclear@0
|
1167 if (!src.colors.empty())
|
nuclear@0
|
1168 {
|
nuclear@0
|
1169 ai_assert(src.colors.size() == src.vertices.size());
|
nuclear@0
|
1170
|
nuclear@0
|
1171 // copy vertex colors
|
nuclear@0
|
1172 mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
|
nuclear@0
|
1173 ::memcpy(mesh->mColors[0],&src.colors[0],
|
nuclear@0
|
1174 sizeof(aiColor4D)*mesh->mNumVertices);
|
nuclear@0
|
1175 }
|
nuclear@0
|
1176
|
nuclear@0
|
1177 if (!src.normals.empty())
|
nuclear@0
|
1178 {
|
nuclear@0
|
1179 ai_assert(src.normals.size() == src.vertices.size());
|
nuclear@0
|
1180
|
nuclear@0
|
1181 // copy normal vectors
|
nuclear@0
|
1182 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
1183 ::memcpy(mesh->mNormals,&src.normals[0],
|
nuclear@0
|
1184 sizeof(aiVector3D)*mesh->mNumVertices);
|
nuclear@0
|
1185 }
|
nuclear@0
|
1186
|
nuclear@0
|
1187 if (!src.uvs.empty())
|
nuclear@0
|
1188 {
|
nuclear@0
|
1189 ai_assert(src.uvs.size() == src.vertices.size());
|
nuclear@0
|
1190
|
nuclear@0
|
1191 // copy texture coordinates
|
nuclear@0
|
1192 mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
1193 ::memcpy(mesh->mTextureCoords[0],&src.uvs[0],
|
nuclear@0
|
1194 sizeof(aiVector3D)*mesh->mNumVertices);
|
nuclear@0
|
1195 }
|
nuclear@0
|
1196
|
nuclear@0
|
1197 // generate faces
|
nuclear@0
|
1198 unsigned int p = 0;
|
nuclear@0
|
1199 aiFace* pFace = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
nuclear@0
|
1200 for (std::vector<unsigned int>::const_iterator it2 = src.faces.begin(),
|
nuclear@0
|
1201 end2 = src.faces.end();
|
nuclear@0
|
1202 it2 != end2;++it2,++pFace)
|
nuclear@0
|
1203 {
|
nuclear@0
|
1204 pFace->mIndices = new unsigned int [ pFace->mNumIndices = *it2 ];
|
nuclear@0
|
1205 for (unsigned int o = 0; o < pFace->mNumIndices;++o)
|
nuclear@0
|
1206 pFace->mIndices[o] = p++;
|
nuclear@0
|
1207 }
|
nuclear@0
|
1208
|
nuclear@0
|
1209 // generate a material for the mesh
|
nuclear@0
|
1210 aiMaterial* pcMat = (aiMaterial*)(pScene->mMaterials[m] = new aiMaterial());
|
nuclear@0
|
1211
|
nuclear@0
|
1212 mesh->mMaterialIndex = m++;
|
nuclear@0
|
1213
|
nuclear@0
|
1214 aiString s;
|
nuclear@0
|
1215 s.Set(AI_DEFAULT_MATERIAL_NAME);
|
nuclear@0
|
1216 pcMat->AddProperty(&s, AI_MATKEY_NAME);
|
nuclear@0
|
1217
|
nuclear@0
|
1218 // FIX: Ignore diffuse == 0
|
nuclear@0
|
1219 aiColor3D c = src.shader.color * (src.shader.diffuse.r ? src.shader.diffuse : aiColor3D(1.f,1.f,1.f));
|
nuclear@0
|
1220 pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
1221 c = src.shader.color * src.shader.specular;
|
nuclear@0
|
1222 pcMat->AddProperty(&c,1,AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
1223
|
nuclear@0
|
1224 // NFF2 - default values for NFF
|
nuclear@0
|
1225 pcMat->AddProperty(&src.shader.ambient, 1,AI_MATKEY_COLOR_AMBIENT);
|
nuclear@0
|
1226 pcMat->AddProperty(&src.shader.emissive,1,AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
1227 pcMat->AddProperty(&src.shader.opacity, 1,AI_MATKEY_OPACITY);
|
nuclear@0
|
1228
|
nuclear@0
|
1229 // setup the first texture layer, if existing
|
nuclear@0
|
1230 if (src.shader.texFile.length())
|
nuclear@0
|
1231 {
|
nuclear@0
|
1232 s.Set(src.shader.texFile);
|
nuclear@0
|
1233 pcMat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
nuclear@0
|
1234
|
nuclear@0
|
1235 if (aiTextureMapping_UV != src.shader.mapping) {
|
nuclear@0
|
1236
|
nuclear@0
|
1237 aiVector3D v(0.f,-1.f,0.f);
|
nuclear@0
|
1238 pcMat->AddProperty(&v, 1,AI_MATKEY_TEXMAP_AXIS_DIFFUSE(0));
|
nuclear@0
|
1239 pcMat->AddProperty((int*)&src.shader.mapping, 1,AI_MATKEY_MAPPING_DIFFUSE(0));
|
nuclear@0
|
1240 }
|
nuclear@0
|
1241 }
|
nuclear@0
|
1242
|
nuclear@0
|
1243 // setup the name of the material
|
nuclear@0
|
1244 if (src.shader.name.length())
|
nuclear@0
|
1245 {
|
nuclear@0
|
1246 s.Set(src.shader.texFile);
|
nuclear@0
|
1247 pcMat->AddProperty(&s,AI_MATKEY_NAME);
|
nuclear@0
|
1248 }
|
nuclear@0
|
1249
|
nuclear@0
|
1250 // setup some more material properties that are specific to NFF2
|
nuclear@0
|
1251 int i;
|
nuclear@0
|
1252 if (src.shader.twoSided)
|
nuclear@0
|
1253 {
|
nuclear@0
|
1254 i = 1;
|
nuclear@0
|
1255 pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
|
nuclear@0
|
1256 }
|
nuclear@0
|
1257 i = (src.shader.shaded ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
|
nuclear@0
|
1258 if (src.shader.shininess)
|
nuclear@0
|
1259 {
|
nuclear@0
|
1260 i = aiShadingMode_Phong;
|
nuclear@0
|
1261 pcMat->AddProperty(&src.shader.shininess,1,AI_MATKEY_SHININESS);
|
nuclear@0
|
1262 }
|
nuclear@0
|
1263 pcMat->AddProperty(&i,1,AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
1264 }
|
nuclear@0
|
1265 pScene->mRootNode = root;
|
nuclear@0
|
1266 }
|
nuclear@0
|
1267
|
nuclear@0
|
1268 #endif // !! ASSIMP_BUILD_NO_NFF_IMPORTER
|