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