1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2016, assimp team
7
8 All rights reserved.
9
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41
42 /** @file Implementation of the material oart of the LWO importer class */
43
44
45
46 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
47
48 // internal headers
49 #include "LWOLoader.h"
50 #include "ByteSwapper.h"
51
52
53 using namespace Assimp;
54
55 // ------------------------------------------------------------------------------------------------
56 template <class T>
lerp(const T & one,const T & two,float val)57 T lerp(const T& one, const T& two, float val)
58 {
59 return one + (two-one)*val;
60 }
61
62 // ------------------------------------------------------------------------------------------------
63 // Convert a lightwave mapping mode to our's
GetMapMode(LWO::Texture::Wrap in)64 inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
65 {
66 switch (in)
67 {
68 case LWO::Texture::REPEAT:
69 return aiTextureMapMode_Wrap;
70
71 case LWO::Texture::MIRROR:
72 return aiTextureMapMode_Mirror;
73
74 case LWO::Texture::RESET:
75 DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
76
77 // fall though here
78 case LWO::Texture::EDGE:
79 return aiTextureMapMode_Clamp;
80 }
81 return (aiTextureMapMode)0;
82 }
83
84 // ------------------------------------------------------------------------------------------------
HandleTextures(aiMaterial * pcMat,const TextureList & in,aiTextureType type)85 bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTextureType type)
86 {
87 ai_assert(NULL != pcMat);
88
89 unsigned int cur = 0, temp = 0;
90 aiString s;
91 bool ret = false;
92
93 for (const auto &texture : in) {
94 if (!texture.enabled || !texture.bCanUse)
95 continue;
96 ret = true;
97
98 // Convert lightwave's mapping modes to ours. We let them
99 // as they are, the GenUVcoords step will compute UV
100 // channels if they're not there.
101
102 aiTextureMapping mapping;
103 switch (texture.mapMode)
104 {
105 case LWO::Texture::Planar:
106 mapping = aiTextureMapping_PLANE;
107 break;
108 case LWO::Texture::Cylindrical:
109 mapping = aiTextureMapping_CYLINDER;
110 break;
111 case LWO::Texture::Spherical:
112 mapping = aiTextureMapping_SPHERE;
113 break;
114 case LWO::Texture::Cubic:
115 mapping = aiTextureMapping_BOX;
116 break;
117 case LWO::Texture::FrontProjection:
118 DefaultLogger::get()->error("LWO2: Unsupported texture mapping: FrontProjection");
119 mapping = aiTextureMapping_OTHER;
120 break;
121 case LWO::Texture::UV:
122 {
123 if( UINT_MAX == texture.mRealUVIndex ) {
124 // We have no UV index for this texture, so we can't display it
125 continue;
126 }
127
128 // add the UV source index
129 temp = texture.mRealUVIndex;
130 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_UVWSRC(type,cur));
131
132 mapping = aiTextureMapping_UV;
133 }
134 break;
135 default:
136 ai_assert(false);
137 };
138
139 if (mapping != aiTextureMapping_UV) {
140 // Setup the main axis
141 aiVector3D v;
142 switch (texture.majorAxis) {
143 case Texture::AXIS_X:
144 v = aiVector3D(1.f,0.f,0.f);
145 break;
146 case Texture::AXIS_Y:
147 v = aiVector3D(0.f,1.f,0.f);
148 break;
149 default: // case Texture::AXIS_Z:
150 v = aiVector3D(0.f,0.f,1.f);
151 break;
152 }
153
154 pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur));
155
156 // Setup UV scalings for cylindric and spherical projections
157 if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) {
158 aiUVTransform trafo;
159 trafo.mScaling.x = texture.wrapAmountW;
160 trafo.mScaling.y = texture.wrapAmountH;
161
162 static_assert(sizeof(aiUVTransform)/sizeof(float) == 5, "sizeof(aiUVTransform)/sizeof(float) == 5");
163 pcMat->AddProperty(&trafo,1,AI_MATKEY_UVTRANSFORM(type,cur));
164 }
165 DefaultLogger::get()->debug("LWO2: Setting up non-UV mapping");
166 }
167
168 // The older LWOB format does not use indirect references to clips.
169 // The file name of a texture is directly specified in the tex chunk.
170 if (mIsLWO2) {
171 // find the corresponding clip (take the last one if multiple
172 // share the same index)
173 ClipList::iterator end = mClips.end(), candidate = end;
174 temp = texture.mClipIdx;
175 for (ClipList::iterator clip = mClips.begin(); clip != end; ++clip) {
176 if ((*clip).idx == temp) {
177 candidate = clip;
178 }
179
180 }
181 if (candidate == end) {
182 DefaultLogger::get()->error("LWO2: Clip index is out of bounds");
183 temp = 0;
184
185 // fixme: apparently some LWO files shipping with Doom3 don't
186 // have clips at all ... check whether that's true or whether
187 // it's a bug in the loader.
188
189 s.Set("$texture.png");
190
191 //continue;
192 }
193 else {
194 if (Clip::UNSUPPORTED == (*candidate).type) {
195 DefaultLogger::get()->error("LWO2: Clip type is not supported");
196 continue;
197 }
198 AdjustTexturePath((*candidate).path);
199 s.Set((*candidate).path);
200
201 // Additional image settings
202 int flags = 0;
203 if ((*candidate).negate) {
204 flags |= aiTextureFlags_Invert;
205 }
206 pcMat->AddProperty(&flags,1,AI_MATKEY_TEXFLAGS(type,cur));
207 }
208 }
209 else
210 {
211 std::string ss = texture.mFileName;
212 if (!ss.length()) {
213 DefaultLogger::get()->error("LWOB: Empty file name");
214 continue;
215 }
216 AdjustTexturePath(ss);
217 s.Set(ss);
218 }
219 pcMat->AddProperty(&s,AI_MATKEY_TEXTURE(type,cur));
220
221 // add the blend factor
222 pcMat->AddProperty<float>(&texture.mStrength,1,AI_MATKEY_TEXBLEND(type,cur));
223
224 // add the blend operation
225 switch (texture.blendType)
226 {
227 case LWO::Texture::Normal:
228 case LWO::Texture::Multiply:
229 temp = (unsigned int)aiTextureOp_Multiply;
230 break;
231
232 case LWO::Texture::Subtractive:
233 case LWO::Texture::Difference:
234 temp = (unsigned int)aiTextureOp_Subtract;
235 break;
236
237 case LWO::Texture::Divide:
238 temp = (unsigned int)aiTextureOp_Divide;
239 break;
240
241 case LWO::Texture::Additive:
242 temp = (unsigned int)aiTextureOp_Add;
243 break;
244
245 default:
246 temp = (unsigned int)aiTextureOp_Multiply;
247 DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
248
249 }
250 // Setup texture operation
251 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
252
253 // setup the mapping mode
254 pcMat->AddProperty<int>((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur));
255
256 // add the u-wrapping
257 temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
258 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_U(type,cur));
259
260 // add the v-wrapping
261 temp = (unsigned int)GetMapMode(texture.wrapModeHeight);
262 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_V(type,cur));
263
264 ++cur;
265 }
266 return ret;
267 }
268
269 // ------------------------------------------------------------------------------------------------
ConvertMaterial(const LWO::Surface & surf,aiMaterial * pcMat)270 void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
271 {
272 // copy the name of the surface
273 aiString st;
274 st.Set(surf.mName);
275 pcMat->AddProperty(&st,AI_MATKEY_NAME);
276
277 const int i = surf.bDoubleSided ? 1 : 0;
278 pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
279
280 // add the refraction index and the bump intensity
281 pcMat->AddProperty(&surf.mIOR,1,AI_MATKEY_REFRACTI);
282 pcMat->AddProperty(&surf.mBumpIntensity,1,AI_MATKEY_BUMPSCALING);
283
284 aiShadingMode m;
285 if (surf.mSpecularValue && surf.mGlossiness)
286 {
287 float fGloss;
288 if (mIsLWO2) {
289 fGloss = std::pow( surf.mGlossiness*10.0f+2.0f, 2.0f);
290 }
291 else
292 {
293 if (16.0f >= surf.mGlossiness)
294 fGloss = 6.0f;
295 else if (64.0f >= surf.mGlossiness)
296 fGloss = 20.0f;
297 else if (256.0f >= surf.mGlossiness)
298 fGloss = 50.0f;
299 else fGloss = 80.0f;
300 }
301
302 pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
303 pcMat->AddProperty(&fGloss,1,AI_MATKEY_SHININESS);
304 m = aiShadingMode_Phong;
305 }
306 else m = aiShadingMode_Gouraud;
307
308 // specular color
309 aiColor3D clr = lerp( aiColor3D(1.f,1.f,1.f), surf.mColor, surf.mColorHighlights );
310 pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR);
311 pcMat->AddProperty(&surf.mSpecularValue,1,AI_MATKEY_SHININESS_STRENGTH);
312
313 // emissive color
314 // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good.
315 clr.g = clr.b = clr.r = surf.mLuminosity*0.8f;
316 pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
317
318 // opacity ... either additive or default-blended, please
319 if (0.f != surf.mAdditiveTransparency) {
320
321 const int add = aiBlendMode_Additive;
322 pcMat->AddProperty(&surf.mAdditiveTransparency,1,AI_MATKEY_OPACITY);
323 pcMat->AddProperty(&add,1,AI_MATKEY_BLEND_FUNC);
324 }
325
326 else if (10e10f != surf.mTransparency) {
327 const int def = aiBlendMode_Default;
328 const float f = 1.0f-surf.mTransparency;
329 pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY);
330 pcMat->AddProperty(&def,1,AI_MATKEY_BLEND_FUNC);
331 }
332
333
334 // ADD TEXTURES to the material
335 // TODO: find out how we can handle COLOR textures correctly...
336 bool b = HandleTextures(pcMat,surf.mColorTextures,aiTextureType_DIFFUSE);
337 b = (b || HandleTextures(pcMat,surf.mDiffuseTextures,aiTextureType_DIFFUSE));
338 HandleTextures(pcMat,surf.mSpecularTextures,aiTextureType_SPECULAR);
339 HandleTextures(pcMat,surf.mGlossinessTextures,aiTextureType_SHININESS);
340 HandleTextures(pcMat,surf.mBumpTextures,aiTextureType_HEIGHT);
341 HandleTextures(pcMat,surf.mOpacityTextures,aiTextureType_OPACITY);
342 HandleTextures(pcMat,surf.mReflectionTextures,aiTextureType_REFLECTION);
343
344 // Now we need to know which shader to use .. iterate through the shader list of
345 // the surface and search for a name which we know ...
346 for (const auto &shader : surf.mShaders) {
347 if (shader.functionName == "LW_SuperCelShader" || shader.functionName == "AH_CelShader") {
348 DefaultLogger::get()->info("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon");
349
350 m = aiShadingMode_Toon;
351 break;
352 }
353 else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") {
354 DefaultLogger::get()->info("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel");
355
356 m = aiShadingMode_Fresnel;
357 break;
358 }
359 else
360 {
361 DefaultLogger::get()->warn("LWO2: Unknown surface shader: " + shader.functionName);
362 }
363 }
364 if (surf.mMaximumSmoothAngle <= 0.0f)
365 m = aiShadingMode_Flat;
366 pcMat->AddProperty((int*)&m,1,AI_MATKEY_SHADING_MODEL);
367
368 // (the diffuse value is just a scaling factor)
369 // If a diffuse texture is set, we set this value to 1.0
370 clr = (b && false ? aiColor3D(1.f,1.f,1.f) : surf.mColor);
371 clr.r *= surf.mDiffuseValue;
372 clr.g *= surf.mDiffuseValue;
373 clr.b *= surf.mDiffuseValue;
374 pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
375 }
376
377 // ------------------------------------------------------------------------------------------------
FindUVChannels(LWO::TextureList & list,LWO::Layer &,LWO::UVChannel & uv,unsigned int next)378 char LWOImporter::FindUVChannels(LWO::TextureList& list,
379 LWO::Layer& /*layer*/,LWO::UVChannel& uv, unsigned int next)
380 {
381 char ret = 0;
382 for (auto &texture : list) {
383
384 // Ignore textures with non-UV mappings for the moment.
385 if (!texture.enabled || !texture.bCanUse || texture.mapMode != LWO::Texture::UV) {
386 continue;
387 }
388
389 if (texture.mUVChannelIndex == uv.name) {
390 ret = 1;
391
392 // got it.
393 if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next)
394 {
395 texture.mRealUVIndex = next;
396 }
397 else {
398 // channel mismatch. need to duplicate the material.
399 DefaultLogger::get()->warn("LWO: Channel mismatch, would need to duplicate surface [design bug]");
400
401 // TODO
402 }
403 }
404 }
405 return ret;
406 }
407
408 // ------------------------------------------------------------------------------------------------
FindUVChannels(LWO::Surface & surf,LWO::SortedRep & sorted,LWO::Layer & layer,unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])409 void LWOImporter::FindUVChannels(LWO::Surface& surf,
410 LWO::SortedRep& sorted,LWO::Layer& layer,
411 unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS])
412 {
413 unsigned int next = 0, extra = 0, num_extra = 0;
414
415 // Check whether we have an UV entry != 0 for one of the faces in 'sorted'
416 for (unsigned int i = 0; i < layer.mUVChannels.size();++i) {
417 LWO::UVChannel& uv = layer.mUVChannels[i];
418
419 for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
420
421 LWO::Face& face = layer.mFaces[*it];
422
423 for (unsigned int n = 0; n < face.mNumIndices; ++n) {
424 unsigned int idx = face.mIndices[n];
425
426 if (uv.abAssigned[idx] && ((aiVector2D*)&uv.rawData[0])[idx] != aiVector2D()) {
427
428 if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
429
430 DefaultLogger::get()->error("LWO: Maximum number of UV channels for "
431 "this mesh reached. Skipping channel \'" + uv.name + "\'");
432
433 }
434 else {
435 // Search through all textures assigned to 'surf' and look for this UV channel
436 char had = 0;
437 had |= FindUVChannels(surf.mColorTextures,layer,uv,next);
438 had |= FindUVChannels(surf.mDiffuseTextures,layer,uv,next);
439 had |= FindUVChannels(surf.mSpecularTextures,layer,uv,next);
440 had |= FindUVChannels(surf.mGlossinessTextures,layer,uv,next);
441 had |= FindUVChannels(surf.mOpacityTextures,layer,uv,next);
442 had |= FindUVChannels(surf.mBumpTextures,layer,uv,next);
443 had |= FindUVChannels(surf.mReflectionTextures,layer,uv,next);
444
445 // We have a texture referencing this UV channel so we have to take special care
446 // and are willing to drop unreferenced channels in favour of it.
447 if (had != 0) {
448 if (num_extra) {
449
450 for (unsigned int a = next; a < std::min( extra, AI_MAX_NUMBER_OF_TEXTURECOORDS-1u ); ++a) {
451 out[a+1] = out[a];
452 }
453 }
454 ++extra;
455 out[next++] = i;
456 }
457 // B�h ... seems not to be used at all. Push to end if enough space is available.
458 else {
459 out[extra++] = i;
460 ++num_extra;
461 }
462 }
463 it = sorted.end()-1;
464 break;
465 }
466 }
467 }
468 }
469 if (extra < AI_MAX_NUMBER_OF_TEXTURECOORDS) {
470 out[extra] = UINT_MAX;
471 }
472 }
473
474 // ------------------------------------------------------------------------------------------------
FindVCChannels(const LWO::Surface & surf,LWO::SortedRep & sorted,const LWO::Layer & layer,unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])475 void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorted, const LWO::Layer& layer,
476 unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS])
477 {
478 unsigned int next = 0;
479
480 // Check whether we have an vc entry != 0 for one of the faces in 'sorted'
481 for (unsigned int i = 0; i < layer.mVColorChannels.size();++i) {
482 const LWO::VColorChannel& vc = layer.mVColorChannels[i];
483
484 if (surf.mVCMap == vc.name) {
485 // The vertex color map is explicitely requested by the surface so we need to take special care of it
486 for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) {
487 out[a+1] = out[a];
488 }
489 out[0] = i;
490 ++next;
491 }
492 else {
493
494 for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) {
495 const LWO::Face& face = layer.mFaces[*it];
496
497 for (unsigned int n = 0; n < face.mNumIndices; ++n) {
498 unsigned int idx = face.mIndices[n];
499
500 if (vc.abAssigned[idx] && ((aiColor4D*)&vc.rawData[0])[idx] != aiColor4D(0.f,0.f,0.f,1.f)) {
501 if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) {
502
503 DefaultLogger::get()->error("LWO: Maximum number of vertex color channels for "
504 "this mesh reached. Skipping channel \'" + vc.name + "\'");
505
506 }
507 else {
508 out[next++] = i;
509 }
510 it = sorted.end()-1;
511 break;
512 }
513 }
514 }
515 }
516 }
517 if (next != AI_MAX_NUMBER_OF_COLOR_SETS) {
518 out[next] = UINT_MAX;
519 }
520 }
521
522 // ------------------------------------------------------------------------------------------------
LoadLWO2ImageMap(unsigned int size,LWO::Texture & tex)523 void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture& tex )
524 {
525 LE_NCONST uint8_t* const end = mFileBuffer + size;
526 while (true)
527 {
528 if (mFileBuffer + 6 >= end)break;
529 LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
530
531 if (mFileBuffer + head.length > end)
532 throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
533
534 uint8_t* const next = mFileBuffer+head.length;
535 switch (head.type)
536 {
537 case AI_LWO_PROJ:
538 tex.mapMode = (Texture::MappingMode)GetU2();
539 break;
540 case AI_LWO_WRAP:
541 tex.wrapModeWidth = (Texture::Wrap)GetU2();
542 tex.wrapModeHeight = (Texture::Wrap)GetU2();
543 break;
544 case AI_LWO_AXIS:
545 tex.majorAxis = (Texture::Axes)GetU2();
546 break;
547 case AI_LWO_IMAG:
548 tex.mClipIdx = GetU2();
549 break;
550 case AI_LWO_VMAP:
551 GetS0(tex.mUVChannelIndex,head.length);
552 break;
553 case AI_LWO_WRPH:
554 tex.wrapAmountH = GetF4();
555 break;
556 case AI_LWO_WRPW:
557 tex.wrapAmountW = GetF4();
558 break;
559 }
560 mFileBuffer = next;
561 }
562 }
563
564 // ------------------------------------------------------------------------------------------------
LoadLWO2Procedural(unsigned int,LWO::Texture & tex)565 void LWOImporter::LoadLWO2Procedural(unsigned int /*size*/, LWO::Texture& tex )
566 {
567 // --- not supported at the moment
568 DefaultLogger::get()->error("LWO2: Found procedural texture, this is not supported");
569 tex.bCanUse = false;
570 }
571
572 // ------------------------------------------------------------------------------------------------
LoadLWO2Gradient(unsigned int,LWO::Texture & tex)573 void LWOImporter::LoadLWO2Gradient(unsigned int /*size*/, LWO::Texture& tex )
574 {
575 // --- not supported at the moment
576 DefaultLogger::get()->error("LWO2: Found gradient texture, this is not supported");
577 tex.bCanUse = false;
578 }
579
580 // ------------------------------------------------------------------------------------------------
LoadLWO2TextureHeader(unsigned int size,LWO::Texture & tex)581 void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
582 {
583 LE_NCONST uint8_t* const end = mFileBuffer + size;
584
585 // get the ordinal string
586 GetS0( tex.ordinal, size);
587
588 // we could crash later if this is an empty string ...
589 if (!tex.ordinal.length())
590 {
591 DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
592 tex.ordinal = "\x00";
593 }
594 while (true)
595 {
596 if (mFileBuffer + 6 >= end)break;
597 const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
598
599 if (mFileBuffer + head.length > end)
600 throw DeadlyImportError("LWO2: Invalid texture header chunk length");
601
602 uint8_t* const next = mFileBuffer+head.length;
603 switch (head.type)
604 {
605 case AI_LWO_CHAN:
606 tex.type = GetU4();
607 break;
608 case AI_LWO_ENAB:
609 tex.enabled = GetU2() ? true : false;
610 break;
611 case AI_LWO_OPAC:
612 tex.blendType = (Texture::BlendType)GetU2();
613 tex.mStrength = GetF4();
614 break;
615 }
616 mFileBuffer = next;
617 }
618 }
619
620 // ------------------------------------------------------------------------------------------------
LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader * head,unsigned int size)621 void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader* head, unsigned int size )
622 {
623 ai_assert(!mSurfaces->empty());
624 LWO::Surface& surf = mSurfaces->back();
625 LWO::Texture tex;
626
627 // load the texture header
628 LoadLWO2TextureHeader(head->length,tex);
629 size -= head->length + 6;
630
631 // now get the exact type of the texture
632 switch (head->type)
633 {
634 case AI_LWO_PROC:
635 LoadLWO2Procedural(size,tex);
636 break;
637 case AI_LWO_GRAD:
638 LoadLWO2Gradient(size,tex);
639 break;
640 case AI_LWO_IMAP:
641 LoadLWO2ImageMap(size,tex);
642 }
643
644 // get the destination channel
645 TextureList* listRef = NULL;
646 switch (tex.type)
647 {
648 case AI_LWO_COLR:
649 listRef = &surf.mColorTextures;break;
650 case AI_LWO_DIFF:
651 listRef = &surf.mDiffuseTextures;break;
652 case AI_LWO_SPEC:
653 listRef = &surf.mSpecularTextures;break;
654 case AI_LWO_GLOS:
655 listRef = &surf.mGlossinessTextures;break;
656 case AI_LWO_BUMP:
657 listRef = &surf.mBumpTextures;break;
658 case AI_LWO_TRAN:
659 listRef = &surf.mOpacityTextures;break;
660 case AI_LWO_REFL:
661 listRef = &surf.mReflectionTextures;break;
662 default:
663 DefaultLogger::get()->warn("LWO2: Encountered unknown texture type");
664 return;
665 }
666
667 // now attach the texture to the parent surface - sort by ordinal string
668 for (TextureList::iterator it = listRef->begin();it != listRef->end(); ++it) {
669 if (::strcmp(tex.ordinal.c_str(),(*it).ordinal.c_str()) < 0) {
670 listRef->insert(it,tex);
671 return;
672 }
673 }
674 listRef->push_back(tex);
675 }
676
677 // ------------------------------------------------------------------------------------------------
LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader *,unsigned int size)678 void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* /*head*/, unsigned int size )
679 {
680 LE_NCONST uint8_t* const end = mFileBuffer + size;
681
682 ai_assert(!mSurfaces->empty());
683 LWO::Surface& surf = mSurfaces->back();
684 LWO::Shader shader;
685
686 // get the ordinal string
687 GetS0( shader.ordinal, size);
688
689 // we could crash later if this is an empty string ...
690 if (!shader.ordinal.length())
691 {
692 DefaultLogger::get()->error("LWO2: Ill-formed SURF.BLOK ordinal string");
693 shader.ordinal = "\x00";
694 }
695
696 // read the header
697 while (true)
698 {
699 if (mFileBuffer + 6 >= end)break;
700 const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
701
702 if (mFileBuffer + head.length > end)
703 throw DeadlyImportError("LWO2: Invalid shader header chunk length");
704
705 uint8_t* const next = mFileBuffer+head.length;
706 switch (head.type)
707 {
708 case AI_LWO_ENAB:
709 shader.enabled = GetU2() ? true : false;
710 break;
711
712 case AI_LWO_FUNC:
713 GetS0( shader.functionName, head.length );
714 }
715 mFileBuffer = next;
716 }
717
718 // now attach the shader to the parent surface - sort by ordinal string
719 for (ShaderList::iterator it = surf.mShaders.begin();it != surf.mShaders.end(); ++it) {
720 if (::strcmp(shader.ordinal.c_str(),(*it).ordinal.c_str()) < 0) {
721 surf.mShaders.insert(it,shader);
722 return;
723 }
724 }
725 surf.mShaders.push_back(shader);
726 }
727
728 // ------------------------------------------------------------------------------------------------
LoadLWO2Surface(unsigned int size)729 void LWOImporter::LoadLWO2Surface(unsigned int size)
730 {
731 LE_NCONST uint8_t* const end = mFileBuffer + size;
732
733 mSurfaces->push_back( LWO::Surface () );
734 LWO::Surface& surf = mSurfaces->back();
735
736 GetS0(surf.mName,size);
737
738 // check whether this surface was derived from any other surface
739 std::string derived;
740 GetS0(derived,(unsigned int)(end - mFileBuffer));
741 if (derived.length()) {
742 // yes, find this surface
743 for (SurfaceList::iterator it = mSurfaces->begin(), end = mSurfaces->end()-1; it != end; ++it) {
744 if ((*it).mName == derived) {
745 // we have it ...
746 surf = *it;
747 derived.clear();break;
748 }
749 }
750 if (derived.size())
751 DefaultLogger::get()->warn("LWO2: Unable to find source surface: " + derived);
752 }
753
754 while (true)
755 {
756 if (mFileBuffer + 6 >= end)
757 break;
758 const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer);
759
760 if (mFileBuffer + head.length > end)
761 throw DeadlyImportError("LWO2: Invalid surface chunk length");
762
763 uint8_t* const next = mFileBuffer+head.length;
764 switch (head.type)
765 {
766 // diffuse color
767 case AI_LWO_COLR:
768 {
769 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,12);
770 surf.mColor.r = GetF4();
771 surf.mColor.g = GetF4();
772 surf.mColor.b = GetF4();
773 break;
774 }
775 // diffuse strength ... hopefully
776 case AI_LWO_DIFF:
777 {
778 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,4);
779 surf.mDiffuseValue = GetF4();
780 break;
781 }
782 // specular strength ... hopefully
783 case AI_LWO_SPEC:
784 {
785 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,4);
786 surf.mSpecularValue = GetF4();
787 break;
788 }
789 // transparency
790 case AI_LWO_TRAN:
791 {
792 // transparency explicitly disabled?
793 if (surf.mTransparency == 10e10f)
794 break;
795
796 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,4);
797 surf.mTransparency = GetF4();
798 break;
799 }
800 // additive transparency
801 case AI_LWO_ADTR:
802 {
803 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,ADTR,4);
804 surf.mAdditiveTransparency = GetF4();
805 break;
806 }
807 // wireframe mode
808 case AI_LWO_LINE:
809 {
810 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LINE,2);
811 if (GetU2() & 0x1)
812 surf.mWireframe = true;
813 break;
814 }
815 // glossiness
816 case AI_LWO_GLOS:
817 {
818 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,4);
819 surf.mGlossiness = GetF4();
820 break;
821 }
822 // bump intensity
823 case AI_LWO_BUMP:
824 {
825 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BUMP,4);
826 surf.mBumpIntensity = GetF4();
827 break;
828 }
829 // color highlights
830 case AI_LWO_CLRH:
831 {
832 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,CLRH,4);
833 surf.mColorHighlights = GetF4();
834 break;
835 }
836 // index of refraction
837 case AI_LWO_RIND:
838 {
839 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,RIND,4);
840 surf.mIOR = GetF4();
841 break;
842 }
843 // polygon sidedness
844 case AI_LWO_SIDE:
845 {
846 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SIDE,2);
847 surf.bDoubleSided = (3 == GetU2());
848 break;
849 }
850 // maximum smoothing angle
851 case AI_LWO_SMAN:
852 {
853 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4);
854 surf.mMaximumSmoothAngle = fabs( GetF4() );
855 break;
856 }
857 // vertex color channel to be applied to the surface
858 case AI_LWO_VCOL:
859 {
860 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,VCOL,12);
861 surf.mDiffuseValue *= GetF4(); // strength
862 ReadVSizedIntLWO2(mFileBuffer); // skip envelope
863 surf.mVCMapType = GetU4(); // type of the channel
864
865 // name of the channel
866 GetS0(surf.mVCMap, (unsigned int) (next - mFileBuffer ));
867 break;
868 }
869 // surface bock entry
870 case AI_LWO_BLOK:
871 {
872 AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,BLOK,4);
873 IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer);
874
875 switch (head2.type)
876 {
877 case AI_LWO_PROC:
878 case AI_LWO_GRAD:
879 case AI_LWO_IMAP:
880 LoadLWO2TextureBlock(&head2, head.length);
881 break;
882 case AI_LWO_SHDR:
883 LoadLWO2ShaderBlock(&head2, head.length);
884 break;
885
886 default:
887 DefaultLogger::get()->warn("LWO2: Found an unsupported surface BLOK");
888 };
889
890 break;
891 }
892 }
893 mFileBuffer = next;
894 }
895 }
896
897 #endif // !! ASSIMP_BUILD_NO_X_IMPORTER
898