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 BaseImporter.cpp
|
nuclear@0
|
43 * @brief Implementation of BaseImporter
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #include "BaseImporter.h"
|
nuclear@0
|
48 #include "FileSystemFilter.h"
|
nuclear@0
|
49
|
nuclear@0
|
50 #include "Importer.h"
|
nuclear@0
|
51
|
nuclear@0
|
52 using namespace Assimp;
|
nuclear@0
|
53
|
nuclear@0
|
54 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
55 // Constructor to be privately used by Importer
|
nuclear@0
|
56 BaseImporter::BaseImporter()
|
nuclear@0
|
57 : progress()
|
nuclear@0
|
58 {
|
nuclear@0
|
59 // nothing to do here
|
nuclear@0
|
60 }
|
nuclear@0
|
61
|
nuclear@0
|
62 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
63 // Destructor, private as well
|
nuclear@0
|
64 BaseImporter::~BaseImporter()
|
nuclear@0
|
65 {
|
nuclear@0
|
66 // nothing to do here
|
nuclear@0
|
67 }
|
nuclear@0
|
68
|
nuclear@0
|
69 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
70 // Imports the given file and returns the imported data.
|
nuclear@0
|
71 aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
|
nuclear@0
|
72 {
|
nuclear@0
|
73 progress = pImp->GetProgressHandler();
|
nuclear@0
|
74 ai_assert(progress);
|
nuclear@0
|
75
|
nuclear@0
|
76 // Gather configuration properties for this run
|
nuclear@0
|
77 SetupProperties( pImp );
|
nuclear@0
|
78
|
nuclear@0
|
79 // Construct a file system filter to improve our success ratio at reading external files
|
nuclear@0
|
80 FileSystemFilter filter(pFile,pIOHandler);
|
nuclear@0
|
81
|
nuclear@0
|
82 // create a scene object to hold the data
|
nuclear@0
|
83 ScopeGuard<aiScene> sc(new aiScene());
|
nuclear@0
|
84
|
nuclear@0
|
85 // dispatch importing
|
nuclear@0
|
86 try
|
nuclear@0
|
87 {
|
nuclear@0
|
88 InternReadFile( pFile, sc, &filter);
|
nuclear@0
|
89
|
nuclear@0
|
90 } catch( const std::exception& err ) {
|
nuclear@0
|
91 // extract error description
|
nuclear@0
|
92 mErrorText = err.what();
|
nuclear@0
|
93 DefaultLogger::get()->error(mErrorText);
|
nuclear@0
|
94 return NULL;
|
nuclear@0
|
95 }
|
nuclear@0
|
96
|
nuclear@0
|
97 // return what we gathered from the import.
|
nuclear@0
|
98 sc.dismiss();
|
nuclear@0
|
99 return sc;
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
103 void BaseImporter::SetupProperties(const Importer* /*pImp*/)
|
nuclear@0
|
104 {
|
nuclear@0
|
105 // the default implementation does nothing
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
109 void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
nuclear@0
|
110 {
|
nuclear@0
|
111 const aiImporterDesc* desc = GetInfo();
|
nuclear@0
|
112 ai_assert(desc != NULL);
|
nuclear@0
|
113
|
nuclear@0
|
114 const char* ext = desc->mFileExtensions;
|
nuclear@0
|
115 ai_assert(ext != NULL);
|
nuclear@0
|
116
|
nuclear@0
|
117 const char* last = ext;
|
nuclear@0
|
118 do {
|
nuclear@0
|
119 if (!*ext || *ext == ' ') {
|
nuclear@0
|
120 extensions.insert(std::string(last,ext-last));
|
nuclear@0
|
121 ai_assert(ext-last > 0);
|
nuclear@0
|
122 last = ext;
|
nuclear@0
|
123 while(*last == ' ') {
|
nuclear@0
|
124 ++last;
|
nuclear@0
|
125 }
|
nuclear@0
|
126 }
|
nuclear@0
|
127 }
|
nuclear@0
|
128 while(*ext++);
|
nuclear@0
|
129 }
|
nuclear@0
|
130
|
nuclear@0
|
131 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
132 /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler,
|
nuclear@0
|
133 const std::string& pFile,
|
nuclear@0
|
134 const char** tokens,
|
nuclear@0
|
135 unsigned int numTokens,
|
nuclear@0
|
136 unsigned int searchBytes /* = 200 */,
|
nuclear@0
|
137 bool tokensSol /* false */)
|
nuclear@0
|
138 {
|
nuclear@0
|
139 ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes);
|
nuclear@0
|
140 if (!pIOHandler)
|
nuclear@0
|
141 return false;
|
nuclear@0
|
142
|
nuclear@0
|
143 boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
nuclear@0
|
144 if (pStream.get() ) {
|
nuclear@0
|
145 // read 200 characters from the file
|
nuclear@0
|
146 boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]);
|
nuclear@0
|
147 char* buffer = _buffer.get();
|
nuclear@0
|
148
|
nuclear@0
|
149 const unsigned int read = pStream->Read(buffer,1,searchBytes);
|
nuclear@0
|
150 if (!read)
|
nuclear@0
|
151 return false;
|
nuclear@0
|
152
|
nuclear@0
|
153 for (unsigned int i = 0; i < read;++i)
|
nuclear@0
|
154 buffer[i] = ::tolower(buffer[i]);
|
nuclear@0
|
155
|
nuclear@0
|
156 // It is not a proper handling of unicode files here ...
|
nuclear@0
|
157 // ehm ... but it works in most cases.
|
nuclear@0
|
158 char* cur = buffer,*cur2 = buffer,*end = &buffer[read];
|
nuclear@0
|
159 while (cur != end) {
|
nuclear@0
|
160 if (*cur)
|
nuclear@0
|
161 *cur2++ = *cur;
|
nuclear@0
|
162 ++cur;
|
nuclear@0
|
163 }
|
nuclear@0
|
164 *cur2 = '\0';
|
nuclear@0
|
165
|
nuclear@0
|
166 for (unsigned int i = 0; i < numTokens;++i) {
|
nuclear@0
|
167 ai_assert(NULL != tokens[i]);
|
nuclear@0
|
168
|
nuclear@0
|
169
|
nuclear@0
|
170 const char* r = strstr(buffer,tokens[i]);
|
nuclear@0
|
171 if (!r)
|
nuclear@0
|
172 continue;
|
nuclear@0
|
173 // We got a match, either we don't care where it is, or it happens to
|
nuclear@0
|
174 // be in the beginning of the file / line
|
nuclear@0
|
175 if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
|
nuclear@0
|
176 DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
|
nuclear@0
|
177 return true;
|
nuclear@0
|
178 }
|
nuclear@0
|
179 }
|
nuclear@0
|
180 }
|
nuclear@0
|
181 return false;
|
nuclear@0
|
182 }
|
nuclear@0
|
183
|
nuclear@0
|
184 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
185 // Simple check for file extension
|
nuclear@0
|
186 /*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile,
|
nuclear@0
|
187 const char* ext0,
|
nuclear@0
|
188 const char* ext1,
|
nuclear@0
|
189 const char* ext2)
|
nuclear@0
|
190 {
|
nuclear@0
|
191 std::string::size_type pos = pFile.find_last_of('.');
|
nuclear@0
|
192
|
nuclear@0
|
193 // no file extension - can't read
|
nuclear@0
|
194 if( pos == std::string::npos)
|
nuclear@0
|
195 return false;
|
nuclear@0
|
196
|
nuclear@0
|
197 const char* ext_real = & pFile[ pos+1 ];
|
nuclear@0
|
198 if( !ASSIMP_stricmp(ext_real,ext0) )
|
nuclear@0
|
199 return true;
|
nuclear@0
|
200
|
nuclear@0
|
201 // check for other, optional, file extensions
|
nuclear@0
|
202 if (ext1 && !ASSIMP_stricmp(ext_real,ext1))
|
nuclear@0
|
203 return true;
|
nuclear@0
|
204
|
nuclear@0
|
205 if (ext2 && !ASSIMP_stricmp(ext_real,ext2))
|
nuclear@0
|
206 return true;
|
nuclear@0
|
207
|
nuclear@0
|
208 return false;
|
nuclear@0
|
209 }
|
nuclear@0
|
210
|
nuclear@0
|
211 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
212 // Get file extension from path
|
nuclear@0
|
213 /*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
|
nuclear@0
|
214 {
|
nuclear@0
|
215 std::string::size_type pos = pFile.find_last_of('.');
|
nuclear@0
|
216
|
nuclear@0
|
217 // no file extension at all
|
nuclear@0
|
218 if( pos == std::string::npos)
|
nuclear@0
|
219 return "";
|
nuclear@0
|
220
|
nuclear@0
|
221 std::string ret = pFile.substr(pos+1);
|
nuclear@0
|
222 std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
|
nuclear@0
|
223 return ret;
|
nuclear@0
|
224 }
|
nuclear@0
|
225
|
nuclear@0
|
226 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
227 // Check for magic bytes at the beginning of the file.
|
nuclear@0
|
228 /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
|
nuclear@0
|
229 const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
|
nuclear@0
|
230 {
|
nuclear@0
|
231 ai_assert(size <= 16 && _magic);
|
nuclear@0
|
232
|
nuclear@0
|
233 if (!pIOHandler) {
|
nuclear@0
|
234 return false;
|
nuclear@0
|
235 }
|
nuclear@0
|
236 union {
|
nuclear@0
|
237 const char* magic;
|
nuclear@0
|
238 const uint16_t* magic_u16;
|
nuclear@0
|
239 const uint32_t* magic_u32;
|
nuclear@0
|
240 };
|
nuclear@0
|
241 magic = reinterpret_cast<const char*>(_magic);
|
nuclear@0
|
242 boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile));
|
nuclear@0
|
243 if (pStream.get() ) {
|
nuclear@0
|
244
|
nuclear@0
|
245 // skip to offset
|
nuclear@0
|
246 pStream->Seek(offset,aiOrigin_SET);
|
nuclear@0
|
247
|
nuclear@0
|
248 // read 'size' characters from the file
|
nuclear@0
|
249 union {
|
nuclear@0
|
250 char data[16];
|
nuclear@0
|
251 uint16_t data_u16[8];
|
nuclear@0
|
252 uint32_t data_u32[4];
|
nuclear@0
|
253 };
|
nuclear@0
|
254 if(size != pStream->Read(data,1,size)) {
|
nuclear@0
|
255 return false;
|
nuclear@0
|
256 }
|
nuclear@0
|
257
|
nuclear@0
|
258 for (unsigned int i = 0; i < num; ++i) {
|
nuclear@0
|
259 // also check against big endian versions of tokens with size 2,4
|
nuclear@0
|
260 // that's just for convinience, the chance that we cause conflicts
|
nuclear@0
|
261 // is quite low and it can save some lines and prevent nasty bugs
|
nuclear@0
|
262 if (2 == size) {
|
nuclear@0
|
263 uint16_t rev = *magic_u16;
|
nuclear@0
|
264 ByteSwap::Swap(&rev);
|
nuclear@0
|
265 if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
|
nuclear@0
|
266 return true;
|
nuclear@0
|
267 }
|
nuclear@0
|
268 }
|
nuclear@0
|
269 else if (4 == size) {
|
nuclear@0
|
270 uint32_t rev = *magic_u32;
|
nuclear@0
|
271 ByteSwap::Swap(&rev);
|
nuclear@0
|
272 if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
|
nuclear@0
|
273 return true;
|
nuclear@0
|
274 }
|
nuclear@0
|
275 }
|
nuclear@0
|
276 else {
|
nuclear@0
|
277 // any length ... just compare
|
nuclear@0
|
278 if(!memcmp(magic,data,size)) {
|
nuclear@0
|
279 return true;
|
nuclear@0
|
280 }
|
nuclear@0
|
281 }
|
nuclear@0
|
282 magic += size;
|
nuclear@0
|
283 }
|
nuclear@0
|
284 }
|
nuclear@0
|
285 return false;
|
nuclear@0
|
286 }
|
nuclear@0
|
287
|
nuclear@0
|
288 #include "ConvertUTF/ConvertUTF.h"
|
nuclear@0
|
289
|
nuclear@0
|
290 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
291 void ReportResult(ConversionResult res)
|
nuclear@0
|
292 {
|
nuclear@0
|
293 if(res == sourceExhausted) {
|
nuclear@0
|
294 DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails");
|
nuclear@0
|
295 }
|
nuclear@0
|
296 else if(res == sourceIllegal) {
|
nuclear@0
|
297 DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails");
|
nuclear@0
|
298 }
|
nuclear@0
|
299 }
|
nuclear@0
|
300
|
nuclear@0
|
301 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
302 // Convert to UTF8 data
|
nuclear@0
|
303 void BaseImporter::ConvertToUTF8(std::vector<char>& data)
|
nuclear@0
|
304 {
|
nuclear@0
|
305 ConversionResult result;
|
nuclear@0
|
306 if(data.size() < 8) {
|
nuclear@0
|
307 throw DeadlyImportError("File is too small");
|
nuclear@0
|
308 }
|
nuclear@0
|
309
|
nuclear@0
|
310 // UTF 8 with BOM
|
nuclear@0
|
311 if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
|
nuclear@0
|
312 DefaultLogger::get()->debug("Found UTF-8 BOM ...");
|
nuclear@0
|
313
|
nuclear@0
|
314 std::copy(data.begin()+3,data.end(),data.begin());
|
nuclear@0
|
315 data.resize(data.size()-3);
|
nuclear@0
|
316 return;
|
nuclear@0
|
317 }
|
nuclear@0
|
318
|
nuclear@0
|
319 // UTF 32 BE with BOM
|
nuclear@0
|
320 if(*((uint32_t*)&data.front()) == 0xFFFE0000) {
|
nuclear@0
|
321
|
nuclear@0
|
322 // swap the endianess ..
|
nuclear@0
|
323 for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) {
|
nuclear@0
|
324 AI_SWAP4P(p);
|
nuclear@0
|
325 }
|
nuclear@0
|
326 }
|
nuclear@0
|
327
|
nuclear@0
|
328 // UTF 32 LE with BOM
|
nuclear@0
|
329 if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
|
nuclear@0
|
330 DefaultLogger::get()->debug("Found UTF-32 BOM ...");
|
nuclear@0
|
331
|
nuclear@0
|
332 const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1;
|
nuclear@0
|
333 char* dstart,*dend;
|
nuclear@0
|
334 std::vector<char> output;
|
nuclear@0
|
335 do {
|
nuclear@0
|
336 output.resize(output.size()?output.size()*3/2:data.size()/2);
|
nuclear@0
|
337 dstart = &output.front(),dend = &output.back()+1;
|
nuclear@0
|
338
|
nuclear@0
|
339 result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
nuclear@0
|
340 } while(result == targetExhausted);
|
nuclear@0
|
341
|
nuclear@0
|
342 ReportResult(result);
|
nuclear@0
|
343
|
nuclear@0
|
344 // copy to output buffer.
|
nuclear@0
|
345 const size_t outlen = (size_t)(dstart-&output.front());
|
nuclear@0
|
346 data.assign(output.begin(),output.begin()+outlen);
|
nuclear@0
|
347 return;
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 // UTF 16 BE with BOM
|
nuclear@0
|
351 if(*((uint16_t*)&data.front()) == 0xFFFE) {
|
nuclear@0
|
352
|
nuclear@0
|
353 // swap the endianess ..
|
nuclear@0
|
354 for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) {
|
nuclear@0
|
355 ByteSwap::Swap2(p);
|
nuclear@0
|
356 }
|
nuclear@0
|
357 }
|
nuclear@0
|
358
|
nuclear@0
|
359 // UTF 16 LE with BOM
|
nuclear@0
|
360 if(*((uint16_t*)&data.front()) == 0xFEFF) {
|
nuclear@0
|
361 DefaultLogger::get()->debug("Found UTF-16 BOM ...");
|
nuclear@0
|
362
|
nuclear@0
|
363 const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1);
|
nuclear@0
|
364 char* dstart,*dend;
|
nuclear@0
|
365 std::vector<char> output;
|
nuclear@0
|
366 do {
|
nuclear@0
|
367 output.resize(output.size()?output.size()*3/2:data.size()*3/4);
|
nuclear@0
|
368 dstart = &output.front(),dend = &output.back()+1;
|
nuclear@0
|
369
|
nuclear@0
|
370 result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion);
|
nuclear@0
|
371 } while(result == targetExhausted);
|
nuclear@0
|
372
|
nuclear@0
|
373 ReportResult(result);
|
nuclear@0
|
374
|
nuclear@0
|
375 // copy to output buffer.
|
nuclear@0
|
376 const size_t outlen = (size_t)(dstart-&output.front());
|
nuclear@0
|
377 data.assign(output.begin(),output.begin()+outlen);
|
nuclear@0
|
378 return;
|
nuclear@0
|
379 }
|
nuclear@0
|
380 }
|
nuclear@0
|
381
|
nuclear@0
|
382 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
383 void BaseImporter::TextFileToBuffer(IOStream* stream,
|
nuclear@0
|
384 std::vector<char>& data)
|
nuclear@0
|
385 {
|
nuclear@0
|
386 ai_assert(NULL != stream);
|
nuclear@0
|
387
|
nuclear@0
|
388 const size_t fileSize = stream->FileSize();
|
nuclear@0
|
389 if(!fileSize) {
|
nuclear@0
|
390 throw DeadlyImportError("File is empty");
|
nuclear@0
|
391 }
|
nuclear@0
|
392
|
nuclear@0
|
393 data.reserve(fileSize+1);
|
nuclear@0
|
394 data.resize(fileSize);
|
nuclear@0
|
395 if(fileSize != stream->Read( &data[0], 1, fileSize)) {
|
nuclear@0
|
396 throw DeadlyImportError("File read error");
|
nuclear@0
|
397 }
|
nuclear@0
|
398
|
nuclear@0
|
399 ConvertToUTF8(data);
|
nuclear@0
|
400
|
nuclear@0
|
401 // append a binary zero to simplify string parsing
|
nuclear@0
|
402 data.push_back(0);
|
nuclear@0
|
403 }
|
nuclear@0
|
404
|
nuclear@0
|
405 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
406 namespace Assimp
|
nuclear@0
|
407 {
|
nuclear@0
|
408 // Represents an import request
|
nuclear@0
|
409 struct LoadRequest
|
nuclear@0
|
410 {
|
nuclear@0
|
411 LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id)
|
nuclear@0
|
412 : file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id)
|
nuclear@0
|
413 {
|
nuclear@0
|
414 if (_map)
|
nuclear@0
|
415 map = *_map;
|
nuclear@0
|
416 }
|
nuclear@0
|
417
|
nuclear@0
|
418 const std::string file;
|
nuclear@0
|
419 unsigned int flags;
|
nuclear@0
|
420 unsigned int refCnt;
|
nuclear@0
|
421 aiScene* scene;
|
nuclear@0
|
422 bool loaded;
|
nuclear@0
|
423 BatchLoader::PropertyMap map;
|
nuclear@0
|
424 unsigned int id;
|
nuclear@0
|
425
|
nuclear@0
|
426 bool operator== (const std::string& f) {
|
nuclear@0
|
427 return file == f;
|
nuclear@0
|
428 }
|
nuclear@0
|
429 };
|
nuclear@0
|
430 }
|
nuclear@0
|
431
|
nuclear@0
|
432 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
433 // BatchLoader::pimpl data structure
|
nuclear@0
|
434 struct Assimp::BatchData
|
nuclear@0
|
435 {
|
nuclear@0
|
436 BatchData()
|
nuclear@0
|
437 : next_id(0xffff)
|
nuclear@0
|
438 {}
|
nuclear@0
|
439
|
nuclear@0
|
440 // IO system to be used for all imports
|
nuclear@0
|
441 IOSystem* pIOSystem;
|
nuclear@0
|
442
|
nuclear@0
|
443 // Importer used to load all meshes
|
nuclear@0
|
444 Importer* pImporter;
|
nuclear@0
|
445
|
nuclear@0
|
446 // List of all imports
|
nuclear@0
|
447 std::list<LoadRequest> requests;
|
nuclear@0
|
448
|
nuclear@0
|
449 // Base path
|
nuclear@0
|
450 std::string pathBase;
|
nuclear@0
|
451
|
nuclear@0
|
452 // Id for next item
|
nuclear@0
|
453 unsigned int next_id;
|
nuclear@0
|
454 };
|
nuclear@0
|
455
|
nuclear@0
|
456 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
457 BatchLoader::BatchLoader(IOSystem* pIO)
|
nuclear@0
|
458 {
|
nuclear@0
|
459 ai_assert(NULL != pIO);
|
nuclear@0
|
460
|
nuclear@0
|
461 data = new BatchData();
|
nuclear@0
|
462 data->pIOSystem = pIO;
|
nuclear@0
|
463
|
nuclear@0
|
464 data->pImporter = new Importer();
|
nuclear@0
|
465 data->pImporter->SetIOHandler(data->pIOSystem);
|
nuclear@0
|
466 }
|
nuclear@0
|
467
|
nuclear@0
|
468 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
469 BatchLoader::~BatchLoader()
|
nuclear@0
|
470 {
|
nuclear@0
|
471 // delete all scenes wthat have not been polled by the user
|
nuclear@0
|
472 for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
nuclear@0
|
473
|
nuclear@0
|
474 delete (*it).scene;
|
nuclear@0
|
475 }
|
nuclear@0
|
476 data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
|
nuclear@0
|
477 delete data->pImporter;
|
nuclear@0
|
478 delete data;
|
nuclear@0
|
479 }
|
nuclear@0
|
480
|
nuclear@0
|
481
|
nuclear@0
|
482 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
483 unsigned int BatchLoader::AddLoadRequest (const std::string& file,
|
nuclear@0
|
484 unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
|
nuclear@0
|
485 {
|
nuclear@0
|
486 ai_assert(!file.empty());
|
nuclear@0
|
487
|
nuclear@0
|
488 // check whether we have this loading request already
|
nuclear@0
|
489 std::list<LoadRequest>::iterator it;
|
nuclear@0
|
490 for (it = data->requests.begin();it != data->requests.end(); ++it) {
|
nuclear@0
|
491
|
nuclear@0
|
492 // Call IOSystem's path comparison function here
|
nuclear@0
|
493 if (data->pIOSystem->ComparePaths((*it).file,file)) {
|
nuclear@0
|
494
|
nuclear@0
|
495 if (map) {
|
nuclear@0
|
496 if (!((*it).map == *map))
|
nuclear@0
|
497 continue;
|
nuclear@0
|
498 }
|
nuclear@0
|
499 else if (!(*it).map.empty())
|
nuclear@0
|
500 continue;
|
nuclear@0
|
501
|
nuclear@0
|
502 (*it).refCnt++;
|
nuclear@0
|
503 return (*it).id;
|
nuclear@0
|
504 }
|
nuclear@0
|
505 }
|
nuclear@0
|
506
|
nuclear@0
|
507 // no, we don't have it. So add it to the queue ...
|
nuclear@0
|
508 data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
|
nuclear@0
|
509 return data->next_id++;
|
nuclear@0
|
510 }
|
nuclear@0
|
511
|
nuclear@0
|
512 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
513 aiScene* BatchLoader::GetImport (unsigned int which)
|
nuclear@0
|
514 {
|
nuclear@0
|
515 for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
nuclear@0
|
516
|
nuclear@0
|
517 if ((*it).id == which && (*it).loaded) {
|
nuclear@0
|
518
|
nuclear@0
|
519 aiScene* sc = (*it).scene;
|
nuclear@0
|
520 if (!(--(*it).refCnt)) {
|
nuclear@0
|
521 data->requests.erase(it);
|
nuclear@0
|
522 }
|
nuclear@0
|
523 return sc;
|
nuclear@0
|
524 }
|
nuclear@0
|
525 }
|
nuclear@0
|
526 return NULL;
|
nuclear@0
|
527 }
|
nuclear@0
|
528
|
nuclear@0
|
529 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
530 void BatchLoader::LoadAll()
|
nuclear@0
|
531 {
|
nuclear@0
|
532 // no threaded implementation for the moment
|
nuclear@0
|
533 for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
|
nuclear@0
|
534 // force validation in debug builds
|
nuclear@0
|
535 unsigned int pp = (*it).flags;
|
nuclear@0
|
536 #ifdef _DEBUG
|
nuclear@0
|
537 pp |= aiProcess_ValidateDataStructure;
|
nuclear@0
|
538 #endif
|
nuclear@0
|
539 // setup config properties if necessary
|
nuclear@0
|
540 ImporterPimpl* pimpl = data->pImporter->Pimpl();
|
nuclear@0
|
541 pimpl->mFloatProperties = (*it).map.floats;
|
nuclear@0
|
542 pimpl->mIntProperties = (*it).map.ints;
|
nuclear@0
|
543 pimpl->mStringProperties = (*it).map.strings;
|
nuclear@0
|
544
|
nuclear@0
|
545 if (!DefaultLogger::isNullLogger())
|
nuclear@0
|
546 {
|
nuclear@0
|
547 DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
|
nuclear@0
|
548 DefaultLogger::get()->info("File: " + (*it).file);
|
nuclear@0
|
549 }
|
nuclear@0
|
550 data->pImporter->ReadFile((*it).file,pp);
|
nuclear@0
|
551 (*it).scene = data->pImporter->GetOrphanedScene();
|
nuclear@0
|
552 (*it).loaded = true;
|
nuclear@0
|
553
|
nuclear@0
|
554 DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
|
nuclear@0
|
555 }
|
nuclear@0
|
556 }
|
nuclear@0
|
557
|
nuclear@0
|
558
|
nuclear@0
|
559
|
nuclear@0
|
560
|