vrshoot

view libs/assimp/LWOMaterial.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
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:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file Implementation of the material oart of the LWO importer class */
45 #include "AssimpPCH.h"
46 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
48 // internal headers
49 #include "LWOLoader.h"
50 #include "ByteSwap.h"
52 using namespace Assimp;
54 // ------------------------------------------------------------------------------------------------
55 template <class T>
56 T lerp(const T& one, const T& two, float val)
57 {
58 return one + (two-one)*val;
59 }
61 // ------------------------------------------------------------------------------------------------
62 // Convert a lightwave mapping mode to our's
63 inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in)
64 {
65 switch (in)
66 {
67 case LWO::Texture::REPEAT:
68 return aiTextureMapMode_Wrap;
70 case LWO::Texture::MIRROR:
71 return aiTextureMapMode_Mirror;
73 case LWO::Texture::RESET:
74 DefaultLogger::get()->warn("LWO2: Unsupported texture map mode: RESET");
76 // fall though here
77 case LWO::Texture::EDGE:
78 return aiTextureMapMode_Clamp;
79 }
80 return (aiTextureMapMode)0;
81 }
83 // ------------------------------------------------------------------------------------------------
84 bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTextureType type)
85 {
86 ai_assert(NULL != pcMat);
88 unsigned int cur = 0, temp = 0;
89 aiString s;
90 bool ret = false;
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;
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.
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 }
127 // add the UV source index
128 temp = (*it).mRealUVIndex;
129 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_UVWSRC(type,cur));
131 mapping = aiTextureMapping_UV;
132 }
133 break;
134 default:
135 ai_assert(false);
136 };
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 }
153 pcMat->AddProperty(&v,1,AI_MATKEY_TEXMAP_AXIS(type,cur));
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;
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 }
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;
177 }
178 if (mClips.end() == clip) {
179 DefaultLogger::get()->error("LWO2: Clip index is out of bounds");
180 temp = 0;
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.
186 s.Set("$texture.png");
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);
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));
218 // add the blend factor
219 pcMat->AddProperty<float>(&(*it).mStrength,1,AI_MATKEY_TEXBLEND(type,cur));
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;
229 case LWO::Texture::Subtractive:
230 case LWO::Texture::Difference:
231 temp = (unsigned int)aiTextureOp_Subtract;
232 break;
234 case LWO::Texture::Divide:
235 temp = (unsigned int)aiTextureOp_Divide;
236 break;
238 case LWO::Texture::Additive:
239 temp = (unsigned int)aiTextureOp_Add;
240 break;
242 default:
243 temp = (unsigned int)aiTextureOp_Multiply;
244 DefaultLogger::get()->warn("LWO2: Unsupported texture blend mode: alpha or displacement");
246 }
247 // Setup texture operation
248 pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
250 // setup the mapping mode
251 pcMat->AddProperty<int>((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur));
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));
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));
261 ++cur;
262 }
263 return ret;
264 }
266 // ------------------------------------------------------------------------------------------------
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);
274 const int i = surf.bDoubleSided ? 1 : 0;
275 pcMat->AddProperty(&i,1,AI_MATKEY_TWOSIDED);
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);
281 aiShadingMode m;
282 if (surf.mSpecularValue && surf.mGlossiness)
283 {
284 float fGloss;
285 if (mIsLWO2) {
286 fGloss = 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 }
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;
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);
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);
315 // opacity ... either additive or default-blended, please
316 if (0.f != surf.mAdditiveTransparency) {
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 }
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 }
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);
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;
346 if ((*it).functionName == "LW_SuperCelShader" || (*it).functionName == "AH_CelShader") {
347 DefaultLogger::get()->info("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon");
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");
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);
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 }
376 // ------------------------------------------------------------------------------------------------
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) {
383 // Ignore textures with non-UV mappings for the moment.
384 if (!(*it).enabled || !(*it).bCanUse || (*it).mapMode != LWO::Texture::UV) {
385 continue;
386 }
388 if ((*it).mUVChannelIndex == uv.name) {
389 ret = 1;
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]");
400 // TODO
401 }
402 }
403 }
404 return ret;
405 }
407 // ------------------------------------------------------------------------------------------------
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;
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];
418 for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) {
420 LWO::Face& face = layer.mFaces[*it];
422 for (unsigned int n = 0; n < face.mNumIndices; ++n) {
423 unsigned int idx = face.mIndices[n];
425 if (uv.abAssigned[idx] && ((aiVector2D*)&uv.rawData[0])[idx] != aiVector2D()) {
427 if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) {
429 DefaultLogger::get()->error("LWO: Maximum number of UV channels for "
430 "this mesh reached. Skipping channel \'" + uv.name + "\'");
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);
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) {
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 }
473 // ------------------------------------------------------------------------------------------------
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;
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];
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 {
493 for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) {
494 const LWO::Face& face = layer.mFaces[*it];
496 for (unsigned int n = 0; n < face.mNumIndices; ++n) {
497 unsigned int idx = face.mIndices[n];
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) {
502 DefaultLogger::get()->error("LWO: Maximum number of vertex color channels for "
503 "this mesh reached. Skipping channel \'" + vc.name + "\'");
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 }
521 // ------------------------------------------------------------------------------------------------
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);
530 if (mFileBuffer + head->length > end)
531 throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length");
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 }
563 // ------------------------------------------------------------------------------------------------
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 }
571 // ------------------------------------------------------------------------------------------------
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 }
579 // ------------------------------------------------------------------------------------------------
580 void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture& tex )
581 {
582 LE_NCONST uint8_t* const end = mFileBuffer + size;
584 // get the ordinal string
585 GetS0( tex.ordinal, size);
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);
598 if (mFileBuffer + head->length > end)
599 throw DeadlyImportError("LWO2: Invalid texture header chunk length");
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 }
619 // ------------------------------------------------------------------------------------------------
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;
626 // load the texture header
627 LoadLWO2TextureHeader(head->length,tex);
628 size -= head->length + 6;
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 }
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 }
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 }
676 // ------------------------------------------------------------------------------------------------
677 void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader* /*head*/, unsigned int size )
678 {
679 LE_NCONST uint8_t* const end = mFileBuffer + size;
681 ai_assert(!mSurfaces->empty());
682 LWO::Surface& surf = mSurfaces->back();
683 LWO::Shader shader;
685 // get the ordinal string
686 GetS0( shader.ordinal, size);
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 }
695 // read the header
696 while (true)
697 {
698 if (mFileBuffer + 6 >= end)break;
699 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
701 if (mFileBuffer + head->length > end)
702 throw DeadlyImportError("LWO2: Invalid shader header chunk length");
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;
711 case AI_LWO_FUNC:
712 GetS0( shader.functionName, head->length );
713 }
714 mFileBuffer = next;
715 }
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 }
727 // ------------------------------------------------------------------------------------------------
728 void LWOImporter::LoadLWO2Surface(unsigned int size)
729 {
730 LE_NCONST uint8_t* const end = mFileBuffer + size;
732 mSurfaces->push_back( LWO::Surface () );
733 LWO::Surface& surf = mSurfaces->back();
735 GetS0(surf.mName,size);
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 }
753 while (true)
754 {
755 if (mFileBuffer + 6 >= end)
756 break;
757 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
759 if (mFileBuffer + head->length > end)
760 throw DeadlyImportError("LWO2: Invalid surface chunk length");
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;
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 = 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
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);
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;
885 default:
886 DefaultLogger::get()->warn("LWO2: Found an unsupported surface BLOK");
887 };
889 break;
890 }
891 }
892 mFileBuffer = next;
893 }
894 }
896 #endif // !! ASSIMP_BUILD_NO_X_IMPORTER