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