rev |
line source |
nuclear@0
|
1
|
nuclear@0
|
2 /*
|
nuclear@0
|
3 ---------------------------------------------------------------------------
|
nuclear@0
|
4 Open Asset Import Library (assimp)
|
nuclear@0
|
5 ---------------------------------------------------------------------------
|
nuclear@0
|
6
|
nuclear@0
|
7 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
8
|
nuclear@0
|
9 All rights reserved.
|
nuclear@0
|
10
|
nuclear@0
|
11 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
12 with or without modification, are permitted provided that the following
|
nuclear@0
|
13 conditions are met:
|
nuclear@0
|
14
|
nuclear@0
|
15 * Redistributions of source code must retain the above
|
nuclear@0
|
16 copyright notice, this list of conditions and the
|
nuclear@0
|
17 following disclaimer.
|
nuclear@0
|
18
|
nuclear@0
|
19 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
20 copyright notice, this list of conditions and the
|
nuclear@0
|
21 following disclaimer in the documentation and/or other
|
nuclear@0
|
22 materials provided with the distribution.
|
nuclear@0
|
23
|
nuclear@0
|
24 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
25 contributors may be used to endorse or promote products
|
nuclear@0
|
26 derived from this software without specific prior
|
nuclear@0
|
27 written permission of the assimp team.
|
nuclear@0
|
28
|
nuclear@0
|
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
40 ---------------------------------------------------------------------------
|
nuclear@0
|
41 */
|
nuclear@0
|
42
|
nuclear@0
|
43 /** @file Implementation of the AC3D importer class */
|
nuclear@0
|
44
|
nuclear@0
|
45 #include "AssimpPCH.h"
|
nuclear@0
|
46
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_AC_IMPORTER
|
nuclear@0
|
48
|
nuclear@0
|
49 // internal headers
|
nuclear@0
|
50 #include "ACLoader.h"
|
nuclear@0
|
51 #include "ParsingUtils.h"
|
nuclear@0
|
52 #include "fast_atof.h"
|
nuclear@0
|
53 #include "Subdivision.h"
|
nuclear@0
|
54
|
nuclear@0
|
55 using namespace Assimp;
|
nuclear@0
|
56
|
nuclear@0
|
57 static const aiImporterDesc desc = {
|
nuclear@0
|
58 "AC3D Importer",
|
nuclear@0
|
59 "",
|
nuclear@0
|
60 "",
|
nuclear@0
|
61 "",
|
nuclear@0
|
62 aiImporterFlags_SupportTextFlavour,
|
nuclear@0
|
63 0,
|
nuclear@0
|
64 0,
|
nuclear@0
|
65 0,
|
nuclear@0
|
66 0,
|
nuclear@0
|
67 "ac acc ac3d"
|
nuclear@0
|
68 };
|
nuclear@0
|
69
|
nuclear@0
|
70 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
71 // skip to the next token
|
nuclear@0
|
72 #define AI_AC_SKIP_TO_NEXT_TOKEN() \
|
nuclear@0
|
73 if (!SkipSpaces(&buffer)) \
|
nuclear@0
|
74 { \
|
nuclear@0
|
75 DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
|
nuclear@0
|
76 continue; \
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
80 // read a string (may be enclosed in double quotation marks). buffer must point to "
|
nuclear@0
|
81 #define AI_AC_GET_STRING(out) \
|
nuclear@0
|
82 ++buffer; \
|
nuclear@0
|
83 const char* sz = buffer; \
|
nuclear@0
|
84 while ('\"' != *buffer) \
|
nuclear@0
|
85 { \
|
nuclear@0
|
86 if (IsLineEnd( *buffer )) \
|
nuclear@0
|
87 { \
|
nuclear@0
|
88 DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
|
nuclear@0
|
89 out = "ERROR"; \
|
nuclear@0
|
90 break; \
|
nuclear@0
|
91 } \
|
nuclear@0
|
92 ++buffer; \
|
nuclear@0
|
93 } \
|
nuclear@0
|
94 if (IsLineEnd( *buffer ))continue; \
|
nuclear@0
|
95 out = std::string(sz,(unsigned int)(buffer-sz)); \
|
nuclear@0
|
96 ++buffer;
|
nuclear@0
|
97
|
nuclear@0
|
98
|
nuclear@0
|
99 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
100 // read 1 to n floats prefixed with an optional predefined identifier
|
nuclear@0
|
101 #define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \
|
nuclear@0
|
102 AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
nuclear@0
|
103 if (name_length) \
|
nuclear@0
|
104 { \
|
nuclear@0
|
105 if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
|
nuclear@0
|
106 { \
|
nuclear@0
|
107 DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
|
nuclear@0
|
108 continue; \
|
nuclear@0
|
109 } \
|
nuclear@0
|
110 buffer += name_length+1; \
|
nuclear@0
|
111 } \
|
nuclear@0
|
112 for (unsigned int i = 0; i < num;++i) \
|
nuclear@0
|
113 { \
|
nuclear@0
|
114 AI_AC_SKIP_TO_NEXT_TOKEN(); \
|
nuclear@0
|
115 buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118
|
nuclear@0
|
119 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
120 // Constructor to be privately used by Importer
|
nuclear@0
|
121 AC3DImporter::AC3DImporter()
|
nuclear@0
|
122 {
|
nuclear@0
|
123 // nothing to be done here
|
nuclear@0
|
124 }
|
nuclear@0
|
125
|
nuclear@0
|
126 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
127 // Destructor, private as well
|
nuclear@0
|
128 AC3DImporter::~AC3DImporter()
|
nuclear@0
|
129 {
|
nuclear@0
|
130 // nothing to be done here
|
nuclear@0
|
131 }
|
nuclear@0
|
132
|
nuclear@0
|
133 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
134 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
135 bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
nuclear@0
|
136 {
|
nuclear@0
|
137 std::string extension = GetExtension(pFile);
|
nuclear@0
|
138
|
nuclear@0
|
139 // fixme: are acc and ac3d *really* used? Some sources say they are
|
nuclear@0
|
140 if(extension == "ac" || extension == "ac3d" || extension == "acc") {
|
nuclear@0
|
141 return true;
|
nuclear@0
|
142 }
|
nuclear@0
|
143 if (!extension.length() || checkSig) {
|
nuclear@0
|
144 uint32_t token = AI_MAKE_MAGIC("AC3D");
|
nuclear@0
|
145 return CheckMagicToken(pIOHandler,pFile,&token,1,0);
|
nuclear@0
|
146 }
|
nuclear@0
|
147 return false;
|
nuclear@0
|
148 }
|
nuclear@0
|
149
|
nuclear@0
|
150 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
151 // Loader meta information
|
nuclear@0
|
152 const aiImporterDesc* AC3DImporter::GetInfo () const
|
nuclear@0
|
153 {
|
nuclear@0
|
154 return &desc;
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
158 // Get a pointer to the next line from the file
|
nuclear@0
|
159 bool AC3DImporter::GetNextLine( )
|
nuclear@0
|
160 {
|
nuclear@0
|
161 SkipLine(&buffer);
|
nuclear@0
|
162 return SkipSpaces(&buffer);
|
nuclear@0
|
163 }
|
nuclear@0
|
164
|
nuclear@0
|
165 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
166 // Parse an object section in an AC file
|
nuclear@0
|
167 void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
nuclear@0
|
168 {
|
nuclear@0
|
169 if (!TokenMatch(buffer,"OBJECT",6))
|
nuclear@0
|
170 return;
|
nuclear@0
|
171
|
nuclear@0
|
172 SkipSpaces(&buffer);
|
nuclear@0
|
173
|
nuclear@0
|
174 ++mNumMeshes;
|
nuclear@0
|
175
|
nuclear@0
|
176 objects.push_back(Object());
|
nuclear@0
|
177 Object& obj = objects.back();
|
nuclear@0
|
178
|
nuclear@0
|
179 aiLight* light = NULL;
|
nuclear@0
|
180 if (!ASSIMP_strincmp(buffer,"light",5))
|
nuclear@0
|
181 {
|
nuclear@0
|
182 // This is a light source. Add it to the list
|
nuclear@0
|
183 mLights->push_back(light = new aiLight());
|
nuclear@0
|
184
|
nuclear@0
|
185 // Return a point light with no attenuation
|
nuclear@0
|
186 light->mType = aiLightSource_POINT;
|
nuclear@0
|
187 light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f);
|
nuclear@0
|
188 light->mAttenuationConstant = 1.f;
|
nuclear@0
|
189
|
nuclear@0
|
190 // Generate a default name for both the light source and the node
|
nuclear@0
|
191 // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version.
|
nuclear@0
|
192 light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
|
nuclear@0
|
193 obj.name = std::string( light->mName.data );
|
nuclear@0
|
194
|
nuclear@0
|
195 DefaultLogger::get()->debug("AC3D: Light source encountered");
|
nuclear@0
|
196 obj.type = Object::Light;
|
nuclear@0
|
197 }
|
nuclear@0
|
198 else if (!ASSIMP_strincmp(buffer,"group",5))
|
nuclear@0
|
199 {
|
nuclear@0
|
200 obj.type = Object::Group;
|
nuclear@0
|
201 }
|
nuclear@0
|
202 else if (!ASSIMP_strincmp(buffer,"world",5))
|
nuclear@0
|
203 {
|
nuclear@0
|
204 obj.type = Object::World;
|
nuclear@0
|
205 }
|
nuclear@0
|
206 else obj.type = Object::Poly;
|
nuclear@0
|
207 while (GetNextLine())
|
nuclear@0
|
208 {
|
nuclear@0
|
209 if (TokenMatch(buffer,"kids",4))
|
nuclear@0
|
210 {
|
nuclear@0
|
211 SkipSpaces(&buffer);
|
nuclear@0
|
212 unsigned int num = strtoul10(buffer,&buffer);
|
nuclear@0
|
213 GetNextLine();
|
nuclear@0
|
214 if (num)
|
nuclear@0
|
215 {
|
nuclear@0
|
216 // load the children of this object recursively
|
nuclear@0
|
217 obj.children.reserve(num);
|
nuclear@0
|
218 for (unsigned int i = 0; i < num; ++i)
|
nuclear@0
|
219 LoadObjectSection(obj.children);
|
nuclear@0
|
220 }
|
nuclear@0
|
221 return;
|
nuclear@0
|
222 }
|
nuclear@0
|
223 else if (TokenMatch(buffer,"name",4))
|
nuclear@0
|
224 {
|
nuclear@0
|
225 SkipSpaces(&buffer);
|
nuclear@0
|
226 AI_AC_GET_STRING(obj.name);
|
nuclear@0
|
227
|
nuclear@0
|
228 // If this is a light source, we'll also need to store
|
nuclear@0
|
229 // the name of the node in it.
|
nuclear@0
|
230 if (light)
|
nuclear@0
|
231 {
|
nuclear@0
|
232 light->mName.Set(obj.name);
|
nuclear@0
|
233 }
|
nuclear@0
|
234 }
|
nuclear@0
|
235 else if (TokenMatch(buffer,"texture",7))
|
nuclear@0
|
236 {
|
nuclear@0
|
237 SkipSpaces(&buffer);
|
nuclear@0
|
238 AI_AC_GET_STRING(obj.texture);
|
nuclear@0
|
239 }
|
nuclear@0
|
240 else if (TokenMatch(buffer,"texrep",6))
|
nuclear@0
|
241 {
|
nuclear@0
|
242 SkipSpaces(&buffer);
|
nuclear@0
|
243 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat);
|
nuclear@0
|
244 if (!obj.texRepeat.x || !obj.texRepeat.y)
|
nuclear@0
|
245 obj.texRepeat = aiVector2D (1.f,1.f);
|
nuclear@0
|
246 }
|
nuclear@0
|
247 else if (TokenMatch(buffer,"texoff",6))
|
nuclear@0
|
248 {
|
nuclear@0
|
249 SkipSpaces(&buffer);
|
nuclear@0
|
250 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset);
|
nuclear@0
|
251 }
|
nuclear@0
|
252 else if (TokenMatch(buffer,"rot",3))
|
nuclear@0
|
253 {
|
nuclear@0
|
254 SkipSpaces(&buffer);
|
nuclear@0
|
255 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation);
|
nuclear@0
|
256 }
|
nuclear@0
|
257 else if (TokenMatch(buffer,"loc",3))
|
nuclear@0
|
258 {
|
nuclear@0
|
259 SkipSpaces(&buffer);
|
nuclear@0
|
260 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation);
|
nuclear@0
|
261 }
|
nuclear@0
|
262 else if (TokenMatch(buffer,"subdiv",6))
|
nuclear@0
|
263 {
|
nuclear@0
|
264 SkipSpaces(&buffer);
|
nuclear@0
|
265 obj.subDiv = strtoul10(buffer,&buffer);
|
nuclear@0
|
266 }
|
nuclear@0
|
267 else if (TokenMatch(buffer,"crease",6))
|
nuclear@0
|
268 {
|
nuclear@0
|
269 SkipSpaces(&buffer);
|
nuclear@0
|
270 obj.crease = fast_atof(buffer);
|
nuclear@0
|
271 }
|
nuclear@0
|
272 else if (TokenMatch(buffer,"numvert",7))
|
nuclear@0
|
273 {
|
nuclear@0
|
274 SkipSpaces(&buffer);
|
nuclear@0
|
275
|
nuclear@0
|
276 unsigned int t = strtoul10(buffer,&buffer);
|
nuclear@0
|
277 obj.vertices.reserve(t);
|
nuclear@0
|
278 for (unsigned int i = 0; i < t;++i)
|
nuclear@0
|
279 {
|
nuclear@0
|
280 if (!GetNextLine())
|
nuclear@0
|
281 {
|
nuclear@0
|
282 DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
|
nuclear@0
|
283 break;
|
nuclear@0
|
284 }
|
nuclear@0
|
285 else if (!IsNumeric(*buffer))
|
nuclear@0
|
286 {
|
nuclear@0
|
287 DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
|
nuclear@0
|
288 --buffer; // make sure the line is processed a second time
|
nuclear@0
|
289 break;
|
nuclear@0
|
290 }
|
nuclear@0
|
291 obj.vertices.push_back(aiVector3D());
|
nuclear@0
|
292 aiVector3D& v = obj.vertices.back();
|
nuclear@0
|
293 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x);
|
nuclear@0
|
294 }
|
nuclear@0
|
295 }
|
nuclear@0
|
296 else if (TokenMatch(buffer,"numsurf",7))
|
nuclear@0
|
297 {
|
nuclear@0
|
298 SkipSpaces(&buffer);
|
nuclear@0
|
299
|
nuclear@0
|
300 bool Q3DWorkAround = false;
|
nuclear@0
|
301
|
nuclear@0
|
302 const unsigned int t = strtoul10(buffer,&buffer);
|
nuclear@0
|
303 obj.surfaces.reserve(t);
|
nuclear@0
|
304 for (unsigned int i = 0; i < t;++i)
|
nuclear@0
|
305 {
|
nuclear@0
|
306 GetNextLine();
|
nuclear@0
|
307 if (!TokenMatch(buffer,"SURF",4))
|
nuclear@0
|
308 {
|
nuclear@0
|
309 // FIX: this can occur for some files - Quick 3D for
|
nuclear@0
|
310 // example writes no surf chunks
|
nuclear@0
|
311 if (!Q3DWorkAround)
|
nuclear@0
|
312 {
|
nuclear@0
|
313 DefaultLogger::get()->warn("AC3D: SURF token was expected");
|
nuclear@0
|
314 DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
|
nuclear@0
|
315 }
|
nuclear@0
|
316 --buffer; // make sure the line is processed a second time
|
nuclear@0
|
317 // break; --- see fix notes above
|
nuclear@0
|
318
|
nuclear@0
|
319 Q3DWorkAround = true;
|
nuclear@0
|
320 }
|
nuclear@0
|
321 SkipSpaces(&buffer);
|
nuclear@0
|
322 obj.surfaces.push_back(Surface());
|
nuclear@0
|
323 Surface& surf = obj.surfaces.back();
|
nuclear@0
|
324 surf.flags = strtoul_cppstyle(buffer);
|
nuclear@0
|
325
|
nuclear@0
|
326 while (1)
|
nuclear@0
|
327 {
|
nuclear@0
|
328 if(!GetNextLine())
|
nuclear@0
|
329 {
|
nuclear@0
|
330 DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete");
|
nuclear@0
|
331 break;
|
nuclear@0
|
332 }
|
nuclear@0
|
333 if (TokenMatch(buffer,"mat",3))
|
nuclear@0
|
334 {
|
nuclear@0
|
335 SkipSpaces(&buffer);
|
nuclear@0
|
336 surf.mat = strtoul10(buffer);
|
nuclear@0
|
337 }
|
nuclear@0
|
338 else if (TokenMatch(buffer,"refs",4))
|
nuclear@0
|
339 {
|
nuclear@0
|
340 // --- see fix notes above
|
nuclear@0
|
341 if (Q3DWorkAround)
|
nuclear@0
|
342 {
|
nuclear@0
|
343 if (!surf.entries.empty())
|
nuclear@0
|
344 {
|
nuclear@0
|
345 buffer -= 6;
|
nuclear@0
|
346 break;
|
nuclear@0
|
347 }
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 SkipSpaces(&buffer);
|
nuclear@0
|
351 const unsigned int m = strtoul10(buffer);
|
nuclear@0
|
352 surf.entries.reserve(m);
|
nuclear@0
|
353
|
nuclear@0
|
354 obj.numRefs += m;
|
nuclear@0
|
355
|
nuclear@0
|
356 for (unsigned int k = 0; k < m; ++k)
|
nuclear@0
|
357 {
|
nuclear@0
|
358 if(!GetNextLine())
|
nuclear@0
|
359 {
|
nuclear@0
|
360 DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
|
nuclear@0
|
361 break;
|
nuclear@0
|
362 }
|
nuclear@0
|
363 surf.entries.push_back(Surface::SurfaceEntry());
|
nuclear@0
|
364 Surface::SurfaceEntry& entry = surf.entries.back();
|
nuclear@0
|
365
|
nuclear@0
|
366 entry.first = strtoul10(buffer,&buffer);
|
nuclear@0
|
367 SkipSpaces(&buffer);
|
nuclear@0
|
368 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second);
|
nuclear@0
|
369 }
|
nuclear@0
|
370 }
|
nuclear@0
|
371 else
|
nuclear@0
|
372 {
|
nuclear@0
|
373
|
nuclear@0
|
374 --buffer; // make sure the line is processed a second time
|
nuclear@0
|
375 break;
|
nuclear@0
|
376 }
|
nuclear@0
|
377 }
|
nuclear@0
|
378 }
|
nuclear@0
|
379 }
|
nuclear@0
|
380 }
|
nuclear@0
|
381 DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
|
nuclear@0
|
382 }
|
nuclear@0
|
383
|
nuclear@0
|
384 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
385 // Convert a material from AC3DImporter::Material to aiMaterial
|
nuclear@0
|
386 void AC3DImporter::ConvertMaterial(const Object& object,
|
nuclear@0
|
387 const Material& matSrc,
|
nuclear@0
|
388 aiMaterial& matDest)
|
nuclear@0
|
389 {
|
nuclear@0
|
390 aiString s;
|
nuclear@0
|
391
|
nuclear@0
|
392 if (matSrc.name.length())
|
nuclear@0
|
393 {
|
nuclear@0
|
394 s.Set(matSrc.name);
|
nuclear@0
|
395 matDest.AddProperty(&s,AI_MATKEY_NAME);
|
nuclear@0
|
396 }
|
nuclear@0
|
397 if (object.texture.length())
|
nuclear@0
|
398 {
|
nuclear@0
|
399 s.Set(object.texture);
|
nuclear@0
|
400 matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
nuclear@0
|
401
|
nuclear@0
|
402 // UV transformation
|
nuclear@0
|
403 if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y ||
|
nuclear@0
|
404 object.texOffset.x || object.texOffset.y)
|
nuclear@0
|
405 {
|
nuclear@0
|
406 aiUVTransform transform;
|
nuclear@0
|
407 transform.mScaling = object.texRepeat;
|
nuclear@0
|
408 transform.mTranslation = object.texOffset;
|
nuclear@0
|
409 matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
|
nuclear@0
|
410 }
|
nuclear@0
|
411 }
|
nuclear@0
|
412
|
nuclear@0
|
413 matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE);
|
nuclear@0
|
414 matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT);
|
nuclear@0
|
415 matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE);
|
nuclear@0
|
416 matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR);
|
nuclear@0
|
417
|
nuclear@0
|
418 int n;
|
nuclear@0
|
419 if (matSrc.shin)
|
nuclear@0
|
420 {
|
nuclear@0
|
421 n = aiShadingMode_Phong;
|
nuclear@0
|
422 matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS);
|
nuclear@0
|
423 }
|
nuclear@0
|
424 else n = aiShadingMode_Gouraud;
|
nuclear@0
|
425 matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL);
|
nuclear@0
|
426
|
nuclear@0
|
427 float f = 1.f - matSrc.trans;
|
nuclear@0
|
428 matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY);
|
nuclear@0
|
429 }
|
nuclear@0
|
430
|
nuclear@0
|
431 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
432 // Converts the loaded data to the internal verbose representation
|
nuclear@0
|
433 aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
nuclear@0
|
434 std::vector<aiMesh*>& meshes,
|
nuclear@0
|
435 std::vector<aiMaterial*>& outMaterials,
|
nuclear@0
|
436 const std::vector<Material>& materials,
|
nuclear@0
|
437 aiNode* parent)
|
nuclear@0
|
438 {
|
nuclear@0
|
439 aiNode* node = new aiNode();
|
nuclear@0
|
440 node->mParent = parent;
|
nuclear@0
|
441 if (object.vertices.size())
|
nuclear@0
|
442 {
|
nuclear@0
|
443 if (!object.surfaces.size() || !object.numRefs)
|
nuclear@0
|
444 {
|
nuclear@0
|
445 /* " An object with 7 vertices (no surfaces, no materials defined).
|
nuclear@0
|
446 This is a good way of getting point data into AC3D.
|
nuclear@0
|
447 The Vertex->create convex-surface/object can be used on these
|
nuclear@0
|
448 vertices to 'wrap' a 3d shape around them "
|
nuclear@0
|
449 (http://www.opencity.info/html/ac3dfileformat.html)
|
nuclear@0
|
450
|
nuclear@0
|
451 therefore: if no surfaces are defined return point data only
|
nuclear@0
|
452 */
|
nuclear@0
|
453
|
nuclear@0
|
454 DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
|
nuclear@0
|
455 "a point list is returned");
|
nuclear@0
|
456
|
nuclear@0
|
457 meshes.push_back(new aiMesh());
|
nuclear@0
|
458 aiMesh* mesh = meshes.back();
|
nuclear@0
|
459
|
nuclear@0
|
460 mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size();
|
nuclear@0
|
461 aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
nuclear@0
|
462 aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
463
|
nuclear@0
|
464 for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts)
|
nuclear@0
|
465 {
|
nuclear@0
|
466 *verts = object.vertices[i];
|
nuclear@0
|
467 faces->mNumIndices = 1;
|
nuclear@0
|
468 faces->mIndices = new unsigned int[1];
|
nuclear@0
|
469 faces->mIndices[0] = i;
|
nuclear@0
|
470 }
|
nuclear@0
|
471
|
nuclear@0
|
472 // use the primary material in this case. this should be the
|
nuclear@0
|
473 // default material if all objects of the file contain points
|
nuclear@0
|
474 // and no faces.
|
nuclear@0
|
475 mesh->mMaterialIndex = 0;
|
nuclear@0
|
476 outMaterials.push_back(new aiMaterial());
|
nuclear@0
|
477 ConvertMaterial(object, materials[0], *outMaterials.back());
|
nuclear@0
|
478 }
|
nuclear@0
|
479 else
|
nuclear@0
|
480 {
|
nuclear@0
|
481 // need to generate one or more meshes for this object.
|
nuclear@0
|
482 // find out how many different materials we have
|
nuclear@0
|
483 typedef std::pair< unsigned int, unsigned int > IntPair;
|
nuclear@0
|
484 typedef std::vector< IntPair > MatTable;
|
nuclear@0
|
485 MatTable needMat(materials.size(),IntPair(0,0));
|
nuclear@0
|
486
|
nuclear@0
|
487 std::vector<Surface>::iterator it,end = object.surfaces.end();
|
nuclear@0
|
488 std::vector<Surface::SurfaceEntry>::iterator it2,end2;
|
nuclear@0
|
489
|
nuclear@0
|
490 for (it = object.surfaces.begin(); it != end; ++it)
|
nuclear@0
|
491 {
|
nuclear@0
|
492 register unsigned int idx = (*it).mat;
|
nuclear@0
|
493 if (idx >= needMat.size())
|
nuclear@0
|
494 {
|
nuclear@0
|
495 DefaultLogger::get()->error("AC3D: material index is out of range");
|
nuclear@0
|
496 idx = 0;
|
nuclear@0
|
497 }
|
nuclear@0
|
498 if ((*it).entries.empty())
|
nuclear@0
|
499 {
|
nuclear@0
|
500 DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
|
nuclear@0
|
501 }
|
nuclear@0
|
502
|
nuclear@0
|
503 // validate all vertex indices to make sure we won't crash here
|
nuclear@0
|
504 for (it2 = (*it).entries.begin(),
|
nuclear@0
|
505 end2 = (*it).entries.end(); it2 != end2; ++it2)
|
nuclear@0
|
506 {
|
nuclear@0
|
507 if ((*it2).first >= object.vertices.size())
|
nuclear@0
|
508 {
|
nuclear@0
|
509 DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
|
nuclear@0
|
510 (*it2).first = 0;
|
nuclear@0
|
511 }
|
nuclear@0
|
512 }
|
nuclear@0
|
513
|
nuclear@0
|
514 if (!needMat[idx].first)++node->mNumMeshes;
|
nuclear@0
|
515
|
nuclear@0
|
516 switch ((*it).flags & 0xf)
|
nuclear@0
|
517 {
|
nuclear@0
|
518 // closed line
|
nuclear@0
|
519 case 0x1:
|
nuclear@0
|
520
|
nuclear@0
|
521 needMat[idx].first += (unsigned int)(*it).entries.size();
|
nuclear@0
|
522 needMat[idx].second += (unsigned int)(*it).entries.size()<<1u;
|
nuclear@0
|
523 break;
|
nuclear@0
|
524
|
nuclear@0
|
525 // unclosed line
|
nuclear@0
|
526 case 0x2:
|
nuclear@0
|
527
|
nuclear@0
|
528 needMat[idx].first += (unsigned int)(*it).entries.size()-1;
|
nuclear@0
|
529 needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u;
|
nuclear@0
|
530 break;
|
nuclear@0
|
531
|
nuclear@0
|
532 // 0 == polygon, else unknown
|
nuclear@0
|
533 default:
|
nuclear@0
|
534
|
nuclear@0
|
535 if ((*it).flags & 0xf)
|
nuclear@0
|
536 {
|
nuclear@0
|
537 DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
|
nuclear@0
|
538 (*it).flags &= ~(0xf);
|
nuclear@0
|
539 }
|
nuclear@0
|
540
|
nuclear@0
|
541 // the number of faces increments by one, the number
|
nuclear@0
|
542 // of vertices by surface.numref.
|
nuclear@0
|
543 needMat[idx].first++;
|
nuclear@0
|
544 needMat[idx].second += (unsigned int)(*it).entries.size();
|
nuclear@0
|
545 };
|
nuclear@0
|
546 }
|
nuclear@0
|
547 unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
|
nuclear@0
|
548 unsigned int mat = 0;
|
nuclear@0
|
549 const size_t oldm = meshes.size();
|
nuclear@0
|
550 for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
|
nuclear@0
|
551 cit != cend; ++cit, ++mat)
|
nuclear@0
|
552 {
|
nuclear@0
|
553 if (!(*cit).first)continue;
|
nuclear@0
|
554
|
nuclear@0
|
555 // allocate a new aiMesh object
|
nuclear@0
|
556 *pip++ = (unsigned int)meshes.size();
|
nuclear@0
|
557 aiMesh* mesh = new aiMesh();
|
nuclear@0
|
558 meshes.push_back(mesh);
|
nuclear@0
|
559
|
nuclear@0
|
560 mesh->mMaterialIndex = (unsigned int)outMaterials.size();
|
nuclear@0
|
561 outMaterials.push_back(new aiMaterial());
|
nuclear@0
|
562 ConvertMaterial(object, materials[mat], *outMaterials.back());
|
nuclear@0
|
563
|
nuclear@0
|
564 // allocate storage for vertices and normals
|
nuclear@0
|
565 mesh->mNumFaces = (*cit).first;
|
nuclear@0
|
566 aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
nuclear@0
|
567
|
nuclear@0
|
568 mesh->mNumVertices = (*cit).second;
|
nuclear@0
|
569 aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
570 unsigned int cur = 0;
|
nuclear@0
|
571
|
nuclear@0
|
572 // allocate UV coordinates, but only if the texture name for the
|
nuclear@0
|
573 // surface is not empty
|
nuclear@0
|
574 aiVector3D* uv = NULL;
|
nuclear@0
|
575 if(object.texture.length())
|
nuclear@0
|
576 {
|
nuclear@0
|
577 uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
578 mesh->mNumUVComponents[0] = 2;
|
nuclear@0
|
579 }
|
nuclear@0
|
580
|
nuclear@0
|
581 for (it = object.surfaces.begin(); it != end; ++it)
|
nuclear@0
|
582 {
|
nuclear@0
|
583 if (mat == (*it).mat)
|
nuclear@0
|
584 {
|
nuclear@0
|
585 const Surface& src = *it;
|
nuclear@0
|
586
|
nuclear@0
|
587 // closed polygon
|
nuclear@0
|
588 unsigned int type = (*it).flags & 0xf;
|
nuclear@0
|
589 if (!type)
|
nuclear@0
|
590 {
|
nuclear@0
|
591 aiFace& face = *faces++;
|
nuclear@0
|
592 if((face.mNumIndices = (unsigned int)src.entries.size()))
|
nuclear@0
|
593 {
|
nuclear@0
|
594 face.mIndices = new unsigned int[face.mNumIndices];
|
nuclear@0
|
595 for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices)
|
nuclear@0
|
596 {
|
nuclear@0
|
597 const Surface::SurfaceEntry& entry = src.entries[i];
|
nuclear@0
|
598 face.mIndices[i] = cur++;
|
nuclear@0
|
599
|
nuclear@0
|
600 // copy vertex positions
|
nuclear@0
|
601 *vertices = object.vertices[entry.first] + object.translation;
|
nuclear@0
|
602
|
nuclear@0
|
603
|
nuclear@0
|
604 // copy texture coordinates
|
nuclear@0
|
605 if (uv)
|
nuclear@0
|
606 {
|
nuclear@0
|
607 uv->x = entry.second.x;
|
nuclear@0
|
608 uv->y = entry.second.y;
|
nuclear@0
|
609 ++uv;
|
nuclear@0
|
610 }
|
nuclear@0
|
611 }
|
nuclear@0
|
612 }
|
nuclear@0
|
613 }
|
nuclear@0
|
614 else
|
nuclear@0
|
615 {
|
nuclear@0
|
616
|
nuclear@0
|
617 it2 = (*it).entries.begin();
|
nuclear@0
|
618
|
nuclear@0
|
619 // either a closed or an unclosed line
|
nuclear@0
|
620 register unsigned int tmp = (unsigned int)(*it).entries.size();
|
nuclear@0
|
621 if (0x2 == type)--tmp;
|
nuclear@0
|
622 for (unsigned int m = 0; m < tmp;++m)
|
nuclear@0
|
623 {
|
nuclear@0
|
624 aiFace& face = *faces++;
|
nuclear@0
|
625
|
nuclear@0
|
626 face.mNumIndices = 2;
|
nuclear@0
|
627 face.mIndices = new unsigned int[2];
|
nuclear@0
|
628 face.mIndices[0] = cur++;
|
nuclear@0
|
629 face.mIndices[1] = cur++;
|
nuclear@0
|
630
|
nuclear@0
|
631 // copy vertex positions
|
nuclear@0
|
632 *vertices++ = object.vertices[(*it2).first];
|
nuclear@0
|
633
|
nuclear@0
|
634 // copy texture coordinates
|
nuclear@0
|
635 if (uv)
|
nuclear@0
|
636 {
|
nuclear@0
|
637 uv->x = (*it2).second.x;
|
nuclear@0
|
638 uv->y = (*it2).second.y;
|
nuclear@0
|
639 ++uv;
|
nuclear@0
|
640 }
|
nuclear@0
|
641
|
nuclear@0
|
642
|
nuclear@0
|
643 if (0x1 == type && tmp-1 == m)
|
nuclear@0
|
644 {
|
nuclear@0
|
645 // if this is a closed line repeat its beginning now
|
nuclear@0
|
646 it2 = (*it).entries.begin();
|
nuclear@0
|
647 }
|
nuclear@0
|
648 else ++it2;
|
nuclear@0
|
649
|
nuclear@0
|
650 // second point
|
nuclear@0
|
651 *vertices++ = object.vertices[(*it2).first];
|
nuclear@0
|
652
|
nuclear@0
|
653 if (uv)
|
nuclear@0
|
654 {
|
nuclear@0
|
655 uv->x = (*it2).second.x;
|
nuclear@0
|
656 uv->y = (*it2).second.y;
|
nuclear@0
|
657 ++uv;
|
nuclear@0
|
658 }
|
nuclear@0
|
659 }
|
nuclear@0
|
660 }
|
nuclear@0
|
661 }
|
nuclear@0
|
662 }
|
nuclear@0
|
663 }
|
nuclear@0
|
664
|
nuclear@0
|
665 // Now apply catmull clark subdivision if necessary. We split meshes into
|
nuclear@0
|
666 // materials which is not done by AC3D during smoothing, so we need to
|
nuclear@0
|
667 // collect all meshes using the same material group.
|
nuclear@0
|
668 if (object.subDiv) {
|
nuclear@0
|
669 if (configEvalSubdivision) {
|
nuclear@0
|
670 boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
|
nuclear@0
|
671 DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
|
nuclear@0
|
672
|
nuclear@0
|
673 std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
|
nuclear@0
|
674 div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
|
nuclear@0
|
675 std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
|
nuclear@0
|
676
|
nuclear@0
|
677 // previous meshes are deleted vy Subdivide().
|
nuclear@0
|
678 }
|
nuclear@0
|
679 else {
|
nuclear@0
|
680 DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
|
nuclear@0
|
681 +object.name);
|
nuclear@0
|
682 }
|
nuclear@0
|
683 }
|
nuclear@0
|
684 }
|
nuclear@0
|
685 }
|
nuclear@0
|
686
|
nuclear@0
|
687 if (object.name.length())
|
nuclear@0
|
688 node->mName.Set(object.name);
|
nuclear@0
|
689 else
|
nuclear@0
|
690 {
|
nuclear@0
|
691 // generate a name depending on the type of the node
|
nuclear@0
|
692 switch (object.type)
|
nuclear@0
|
693 {
|
nuclear@0
|
694 case Object::Group:
|
nuclear@0
|
695 node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++);
|
nuclear@0
|
696 break;
|
nuclear@0
|
697 case Object::Poly:
|
nuclear@0
|
698 node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++);
|
nuclear@0
|
699 break;
|
nuclear@0
|
700 case Object::Light:
|
nuclear@0
|
701 node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++);
|
nuclear@0
|
702 break;
|
nuclear@0
|
703
|
nuclear@0
|
704 // there shouldn't be more than one world, but we don't care
|
nuclear@0
|
705 case Object::World:
|
nuclear@0
|
706 node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++);
|
nuclear@0
|
707 break;
|
nuclear@0
|
708 }
|
nuclear@0
|
709 }
|
nuclear@0
|
710
|
nuclear@0
|
711
|
nuclear@0
|
712 // setup the local transformation matrix of the object
|
nuclear@0
|
713 // compute the transformation offset to the parent node
|
nuclear@0
|
714 node->mTransformation = aiMatrix4x4 ( object.rotation );
|
nuclear@0
|
715
|
nuclear@0
|
716 if (object.type == Object::Group || !object.numRefs)
|
nuclear@0
|
717 {
|
nuclear@0
|
718 node->mTransformation.a4 = object.translation.x;
|
nuclear@0
|
719 node->mTransformation.b4 = object.translation.y;
|
nuclear@0
|
720 node->mTransformation.c4 = object.translation.z;
|
nuclear@0
|
721 }
|
nuclear@0
|
722
|
nuclear@0
|
723 // add children to the object
|
nuclear@0
|
724 if (object.children.size())
|
nuclear@0
|
725 {
|
nuclear@0
|
726 node->mNumChildren = (unsigned int)object.children.size();
|
nuclear@0
|
727 node->mChildren = new aiNode*[node->mNumChildren];
|
nuclear@0
|
728 for (unsigned int i = 0; i < node->mNumChildren;++i)
|
nuclear@0
|
729 {
|
nuclear@0
|
730 node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node);
|
nuclear@0
|
731 }
|
nuclear@0
|
732 }
|
nuclear@0
|
733
|
nuclear@0
|
734 return node;
|
nuclear@0
|
735 }
|
nuclear@0
|
736
|
nuclear@0
|
737 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
738 void AC3DImporter::SetupProperties(const Importer* pImp)
|
nuclear@0
|
739 {
|
nuclear@0
|
740 configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
|
nuclear@0
|
741 configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
|
nuclear@0
|
742 }
|
nuclear@0
|
743
|
nuclear@0
|
744 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
745 // Imports the given file into the given scene structure.
|
nuclear@0
|
746 void AC3DImporter::InternReadFile( const std::string& pFile,
|
nuclear@0
|
747 aiScene* pScene, IOSystem* pIOHandler)
|
nuclear@0
|
748 {
|
nuclear@0
|
749 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
nuclear@0
|
750
|
nuclear@0
|
751 // Check whether we can read from the file
|
nuclear@0
|
752 if( file.get() == NULL)
|
nuclear@0
|
753 throw DeadlyImportError( "Failed to open AC3D file " + pFile + ".");
|
nuclear@0
|
754
|
nuclear@0
|
755 // allocate storage and copy the contents of the file to a memory buffer
|
nuclear@0
|
756 std::vector<char> mBuffer2;
|
nuclear@0
|
757 TextFileToBuffer(file.get(),mBuffer2);
|
nuclear@0
|
758
|
nuclear@0
|
759 buffer = &mBuffer2[0];
|
nuclear@0
|
760 mNumMeshes = 0;
|
nuclear@0
|
761
|
nuclear@0
|
762 lights = polys = worlds = groups = 0;
|
nuclear@0
|
763
|
nuclear@0
|
764 if (::strncmp(buffer,"AC3D",4)) {
|
nuclear@0
|
765 throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found");
|
nuclear@0
|
766 }
|
nuclear@0
|
767
|
nuclear@0
|
768 // print the file format version to the console
|
nuclear@0
|
769 unsigned int version = HexDigitToDecimal( buffer[4] );
|
nuclear@0
|
770 char msg[3];
|
nuclear@0
|
771 ASSIMP_itoa10(msg,3,version);
|
nuclear@0
|
772 DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
|
nuclear@0
|
773
|
nuclear@0
|
774 std::vector<Material> materials;
|
nuclear@0
|
775 materials.reserve(5);
|
nuclear@0
|
776
|
nuclear@0
|
777 std::vector<Object> rootObjects;
|
nuclear@0
|
778 rootObjects.reserve(5);
|
nuclear@0
|
779
|
nuclear@0
|
780 std::vector<aiLight*> lights;
|
nuclear@0
|
781 mLights = & lights;
|
nuclear@0
|
782
|
nuclear@0
|
783 while (GetNextLine())
|
nuclear@0
|
784 {
|
nuclear@0
|
785 if (TokenMatch(buffer,"MATERIAL",8))
|
nuclear@0
|
786 {
|
nuclear@0
|
787 materials.push_back(Material());
|
nuclear@0
|
788 Material& mat = materials.back();
|
nuclear@0
|
789
|
nuclear@0
|
790 // manually parse the material ... sscanf would use the buldin atof ...
|
nuclear@0
|
791 // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f
|
nuclear@0
|
792
|
nuclear@0
|
793 AI_AC_SKIP_TO_NEXT_TOKEN();
|
nuclear@0
|
794 if ('\"' == *buffer)
|
nuclear@0
|
795 {
|
nuclear@0
|
796 AI_AC_GET_STRING(mat.name);
|
nuclear@0
|
797 AI_AC_SKIP_TO_NEXT_TOKEN();
|
nuclear@0
|
798 }
|
nuclear@0
|
799
|
nuclear@0
|
800 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb);
|
nuclear@0
|
801 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb);
|
nuclear@0
|
802 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis);
|
nuclear@0
|
803 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec);
|
nuclear@0
|
804 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin);
|
nuclear@0
|
805 AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans);
|
nuclear@0
|
806 }
|
nuclear@0
|
807 LoadObjectSection(rootObjects);
|
nuclear@0
|
808 }
|
nuclear@0
|
809
|
nuclear@0
|
810 if (rootObjects.empty() || !mNumMeshes)
|
nuclear@0
|
811 {
|
nuclear@0
|
812 throw DeadlyImportError("AC3D: No meshes have been loaded");
|
nuclear@0
|
813 }
|
nuclear@0
|
814 if (materials.empty())
|
nuclear@0
|
815 {
|
nuclear@0
|
816 DefaultLogger::get()->warn("AC3D: No material has been found");
|
nuclear@0
|
817 materials.push_back(Material());
|
nuclear@0
|
818 }
|
nuclear@0
|
819
|
nuclear@0
|
820 mNumMeshes += (mNumMeshes>>2u) + 1;
|
nuclear@0
|
821 std::vector<aiMesh*> meshes;
|
nuclear@0
|
822 meshes.reserve(mNumMeshes);
|
nuclear@0
|
823
|
nuclear@0
|
824 std::vector<aiMaterial*> omaterials;
|
nuclear@0
|
825 materials.reserve(mNumMeshes);
|
nuclear@0
|
826
|
nuclear@0
|
827 // generate a dummy root if there are multiple objects on the top layer
|
nuclear@0
|
828 Object* root;
|
nuclear@0
|
829 if (1 == rootObjects.size())
|
nuclear@0
|
830 root = &rootObjects[0];
|
nuclear@0
|
831 else
|
nuclear@0
|
832 {
|
nuclear@0
|
833 root = new Object();
|
nuclear@0
|
834 }
|
nuclear@0
|
835
|
nuclear@0
|
836 // now convert the imported stuff to our output data structure
|
nuclear@0
|
837 pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials);
|
nuclear@0
|
838 if (1 != rootObjects.size())delete root;
|
nuclear@0
|
839
|
nuclear@0
|
840 if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4))
|
nuclear@0
|
841 pScene->mRootNode->mName.Set("<AC3DWorld>");
|
nuclear@0
|
842
|
nuclear@0
|
843 // copy meshes
|
nuclear@0
|
844 if (meshes.empty())
|
nuclear@0
|
845 {
|
nuclear@0
|
846 throw DeadlyImportError("An unknown error occured during converting");
|
nuclear@0
|
847 }
|
nuclear@0
|
848 pScene->mNumMeshes = (unsigned int)meshes.size();
|
nuclear@0
|
849 pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
nuclear@0
|
850 ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*));
|
nuclear@0
|
851
|
nuclear@0
|
852 // copy materials
|
nuclear@0
|
853 pScene->mNumMaterials = (unsigned int)omaterials.size();
|
nuclear@0
|
854 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
nuclear@0
|
855 ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*));
|
nuclear@0
|
856
|
nuclear@0
|
857 // copy lights
|
nuclear@0
|
858 pScene->mNumLights = (unsigned int)lights.size();
|
nuclear@0
|
859 if (lights.size())
|
nuclear@0
|
860 {
|
nuclear@0
|
861 pScene->mLights = new aiLight*[lights.size()];
|
nuclear@0
|
862 ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*));
|
nuclear@0
|
863 }
|
nuclear@0
|
864 }
|
nuclear@0
|
865
|
nuclear@0
|
866 #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER
|