1/*
2---------------------------------------------------------------------------
3Open Asset Import Library (assimp)
4---------------------------------------------------------------------------
5
6Copyright (c) 2006-2017, assimp team
7
8
9All rights reserved.
10
11Redistribution and use of this software in source and binary forms,
12with or without modification, are permitted provided that the following
13conditions are met:
14
15* Redistributions of source code must retain the above
16 copyright notice, this list of conditions and the
17 following disclaimer.
18
19* Redistributions in binary form must reproduce the above
20 copyright notice, this list of conditions and the
21 following disclaimer in the documentation and/or other
22 materials provided with the distribution.
23
24* Neither the name of the assimp team, nor the names of its
25 contributors may be used to endorse or promote products
26 derived from this software without specific prior
27 written permission of the assimp team.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40---------------------------------------------------------------------------
41*/
42
43/** @file Implementation of the LWO importer class for the older LWOB
44 file formats, including materials */
45
46
47#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
48
49// Internal headers
50#include "LWOLoader.h"
51using namespace Assimp;
52
53
54// ------------------------------------------------------------------------------------------------
55void LWOImporter::LoadLWOBFile()
56{
57 LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
58 bool running = true;
59 while (running)
60 {
61 if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
62 const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer);
63
64 if (mFileBuffer + head.length > end)
65 {
66 throw DeadlyImportError("LWOB: Invalid chunk length");
67 break;
68 }
69 uint8_t* const next = mFileBuffer+head.length;
70 switch (head.type)
71 {
72 // vertex list
73 case AI_LWO_PNTS:
74 {
75 if (!mCurLayer->mTempPoints.empty())
76 DefaultLogger::get()->warn("LWO: PNTS chunk encountered twice");
77 else LoadLWOPoints(head.length);
78 break;
79 }
80 // face list
81 case AI_LWO_POLS:
82 {
83
84 if (!mCurLayer->mFaces.empty())
85 DefaultLogger::get()->warn("LWO: POLS chunk encountered twice");
86 else LoadLWOBPolygons(head.length);
87 break;
88 }
89 // list of tags
90 case AI_LWO_SRFS:
91 {
92 if (!mTags->empty())
93 DefaultLogger::get()->warn("LWO: SRFS chunk encountered twice");
94 else LoadLWOTags(head.length);
95 break;
96 }
97
98 // surface chunk
99 case AI_LWO_SURF:
100 {
101 LoadLWOBSurface(head.length);
102 break;
103 }
104 }
105 mFileBuffer = next;
106 }
107}
108
109// ------------------------------------------------------------------------------------------------
110void LWOImporter::LoadLWOBPolygons(unsigned int length)
111{
112 // first find out how many faces and vertices we'll finally need
113 LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
114 LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer;
115
116 // perform endianness conversions
117#ifndef AI_BUILD_BIG_ENDIAN
118 while (cursor < end)ByteSwap::Swap2(cursor++);
119 cursor = (LE_NCONST uint16_t*)mFileBuffer;
120#endif
121
122 unsigned int iNumFaces = 0,iNumVertices = 0;
123 CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end);
124
125 // allocate the output array and copy face indices
126 if (iNumFaces)
127 {
128 cursor = (LE_NCONST uint16_t*)mFileBuffer;
129
130 mCurLayer->mFaces.resize(iNumFaces);
131 FaceList::iterator it = mCurLayer->mFaces.begin();
132 CopyFaceIndicesLWOB(it,cursor,end);
133 }
134}
135
136// ------------------------------------------------------------------------------------------------
137void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces,
138 LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max)
139{
140 while (cursor < end && max--)
141 {
142 uint16_t numIndices;
143 // must have 2 shorts left for numIndices and surface
144 if (end - cursor < 2) {
145 throw DeadlyImportError("LWOB: Unexpected end of file");
146 }
147 ::memcpy(&numIndices, cursor++, 2);
148 // must have enough left for indices and surface
149 if (end - cursor < (1 + numIndices)) {
150 throw DeadlyImportError("LWOB: Unexpected end of file");
151 }
152 verts += numIndices;
153 faces++;
154 cursor += numIndices;
155 int16_t surface;
156 ::memcpy(&surface, cursor++, 2);
157 if (surface < 0)
158 {
159 // there are detail polygons
160 ::memcpy(&numIndices, cursor++, 2);
161 CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices);
162 }
163 }
164}
165
166// ------------------------------------------------------------------------------------------------
167void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it,
168 LE_NCONST uint16_t*& cursor,
169 const uint16_t* const end,
170 unsigned int max)
171{
172 while (cursor < end && max--)
173 {
174 LWO::Face& face = *it;++it;
175 uint16_t numIndices;
176 ::memcpy(&numIndices, cursor++, 2);
177 face.mNumIndices = numIndices;
178 if(face.mNumIndices)
179 {
180 if (cursor + face.mNumIndices >= end)
181 {
182 break;
183 }
184 face.mIndices = new unsigned int[face.mNumIndices];
185 for (unsigned int i = 0; i < face.mNumIndices;++i)
186 {
187 unsigned int & mi = face.mIndices[i];
188 uint16_t index;
189 ::memcpy(&index, cursor++, 2);
190 mi = index;
191 if (mi > mCurLayer->mTempPoints.size())
192 {
193 DefaultLogger::get()->warn("LWOB: face index is out of range");
194 mi = (unsigned int)mCurLayer->mTempPoints.size()-1;
195 }
196 }
197 }
198 else DefaultLogger::get()->warn("LWOB: Face has 0 indices");
199 int16_t surface;
200 ::memcpy(&surface, cursor++, 2);
201 if (surface < 0)
202 {
203 surface = -surface;
204
205 // there are detail polygons.
206 uint16_t numPolygons;
207 ::memcpy(&numPolygons, cursor++, 2);
208 if (cursor < end)
209 {
210 CopyFaceIndicesLWOB(it,cursor,end,numPolygons);
211 }
212 }
213 face.surfaceIndex = surface-1;
214 }
215}
216
217// ------------------------------------------------------------------------------------------------
218LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size)
219{
220 list.push_back(LWO::Texture());
221 LWO::Texture* tex = &list.back();
222
223 std::string type;
224 GetS0(type,size);
225 const char* s = type.c_str();
226
227 if(strstr(s, "Image Map"))
228 {
229 // Determine mapping type
230 if(strstr(s, "Planar"))
231 tex->mapMode = LWO::Texture::Planar;
232 else if(strstr(s, "Cylindrical"))
233 tex->mapMode = LWO::Texture::Cylindrical;
234 else if(strstr(s, "Spherical"))
235 tex->mapMode = LWO::Texture::Spherical;
236 else if(strstr(s, "Cubic"))
237 tex->mapMode = LWO::Texture::Cubic;
238 else if(strstr(s, "Front"))
239 tex->mapMode = LWO::Texture::FrontProjection;
240 }
241 else
242 {
243 // procedural or gradient, not supported
244 DefaultLogger::get()->error("LWOB: Unsupported legacy texture: " + type);
245 }
246
247 return tex;
248}
249
250// ------------------------------------------------------------------------------------------------
251void LWOImporter::LoadLWOBSurface(unsigned int size)
252{
253 LE_NCONST uint8_t* const end = mFileBuffer + size;
254
255 mSurfaces->push_back( LWO::Surface () );
256 LWO::Surface& surf = mSurfaces->back();
257 LWO::Texture* pTex = NULL;
258
259 GetS0(surf.mName,size);
260 bool running = true;
261 while (running) {
262 if (mFileBuffer + 6 >= end)
263 break;
264
265 IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
266
267 /* A single test file (sonycam.lwo) seems to have invalid surface chunks.
268 * I'm assuming it's the fault of a single, unknown exporter so there are
269 * probably THOUSANDS of them. Here's a dirty workaround:
270 *
271 * We don't break if the chunk limit is exceeded. Instead, we're computing
272 * how much storage is actually left and work with this value from now on.
273 */
274 if (mFileBuffer + head.length > end) {
275 DefaultLogger::get()->error("LWOB: Invalid surface chunk length. Trying to continue.");
276 head.length = (uint16_t) (end - mFileBuffer);
277 }
278
279 uint8_t* const next = mFileBuffer+head.length;
280 switch (head.type)
281 {
282 // diffuse color
283 case AI_LWO_COLR:
284 {
285 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3);
286 surf.mColor.r = GetU1() / 255.0f;
287 surf.mColor.g = GetU1() / 255.0f;
288 surf.mColor.b = GetU1() / 255.0f;
289 break;
290 }
291 // diffuse strength ...
292 case AI_LWO_DIFF:
293 {
294 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2);
295 surf.mDiffuseValue = GetU2() / 255.0f;
296 break;
297 }
298 // specular strength ...
299 case AI_LWO_SPEC:
300 {
301 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2);
302 surf.mSpecularValue = GetU2() / 255.0f;
303 break;
304 }
305 // luminosity ...
306 case AI_LWO_LUMI:
307 {
308 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2);
309 surf.mLuminosity = GetU2() / 255.0f;
310 break;
311 }
312 // transparency
313 case AI_LWO_TRAN:
314 {
315 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2);
316 surf.mTransparency = GetU2() / 255.0f;
317 break;
318 }
319 // surface flags
320 case AI_LWO_FLAG:
321 {
322 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2);
323 uint16_t flag = GetU2();
324 if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f;
325 if (flag & 0x8 ) surf.mColorHighlights = 1.f;
326 if (flag & 0x100) surf.bDoubleSided = true;
327 break;
328 }
329 // maximum smoothing angle
330 case AI_LWO_SMAN:
331 {
332 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
333 surf.mMaximumSmoothAngle = std::fabs( GetF4() );
334 break;
335 }
336 // glossiness
337 case AI_LWO_GLOS:
338 {
339 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2);
340 surf.mGlossiness = (float)GetU2();
341 break;
342 }
343 // color texture
344 case AI_LWO_CTEX:
345 {
346 pTex = SetupNewTextureLWOB(surf.mColorTextures,
347 head.length);
348 break;
349 }
350 // diffuse texture
351 case AI_LWO_DTEX:
352 {
353 pTex = SetupNewTextureLWOB(surf.mDiffuseTextures,
354 head.length);
355 break;
356 }
357 // specular texture
358 case AI_LWO_STEX:
359 {
360 pTex = SetupNewTextureLWOB(surf.mSpecularTextures,
361 head.length);
362 break;
363 }
364 // bump texture
365 case AI_LWO_BTEX:
366 {
367 pTex = SetupNewTextureLWOB(surf.mBumpTextures,
368 head.length);
369 break;
370 }
371 // transparency texture
372 case AI_LWO_TTEX:
373 {
374 pTex = SetupNewTextureLWOB(surf.mOpacityTextures,
375 head.length);
376 break;
377 }
378 // texture path
379 case AI_LWO_TIMG:
380 {
381 if (pTex) {
382 GetS0(pTex->mFileName,head.length);
383 }
384 else DefaultLogger::get()->warn("LWOB: Unexpected TIMG chunk");
385 break;
386 }
387 // texture strength
388 case AI_LWO_TVAL:
389 {
390 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1);
391 if (pTex) {
392 pTex->mStrength = (float)GetU1()/ 255.f;
393 }
394 else DefaultLogger::get()->warn("LWOB: Unexpected TVAL chunk");
395 break;
396 }
397 // texture flags
398 case AI_LWO_TFLG:
399 {
400 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TFLG,2);
401
402 if (pTex)
403 {
404 const uint16_t s = GetU2();
405 if (s & 1)
406 pTex->majorAxis = LWO::Texture::AXIS_X;
407 else if (s & 2)
408 pTex->majorAxis = LWO::Texture::AXIS_Y;
409 else if (s & 4)
410 pTex->majorAxis = LWO::Texture::AXIS_Z;
411
412 if (s & 16)
413 DefaultLogger::get()->warn("LWOB: Ignoring \'negate\' flag on texture");
414 }
415 else DefaultLogger::get()->warn("LWOB: Unexpected TFLG chunk");
416 break;
417 }
418 }
419 mFileBuffer = next;
420 }
421}
422
423#endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER
424