/src/assimp/code/AssetLib/LWO/LWOMaterial.cpp
Line | Count | Source |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2026, 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 | | #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER |
45 | | |
46 | | // internal headers |
47 | | #include "LWOLoader.h" |
48 | | #include <assimp/ByteSwapper.h> |
49 | | |
50 | | using namespace Assimp; |
51 | | |
52 | | // ------------------------------------------------------------------------------------------------ |
53 | | template <class T> |
54 | 618 | T lerp(const T &one, const T &two, float val) { |
55 | 618 | return one + (two - one) * val; |
56 | 618 | } |
57 | | |
58 | | // ------------------------------------------------------------------------------------------------ |
59 | | // Convert a lightwave mapping mode to our's |
60 | 338 | inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) { |
61 | 338 | switch (in) { |
62 | 338 | case LWO::Texture::REPEAT: |
63 | 338 | return aiTextureMapMode_Wrap; |
64 | | |
65 | 0 | case LWO::Texture::MIRROR: |
66 | 0 | return aiTextureMapMode_Mirror; |
67 | | |
68 | 0 | case LWO::Texture::RESET: |
69 | 0 | ASSIMP_LOG_WARN("LWO2: Unsupported texture map mode: RESET"); |
70 | | |
71 | | // fall though here |
72 | 0 | case LWO::Texture::EDGE: |
73 | 0 | return aiTextureMapMode_Clamp; |
74 | 338 | } |
75 | 0 | return (aiTextureMapMode)0; |
76 | 338 | } |
77 | | |
78 | | // ------------------------------------------------------------------------------------------------ |
79 | 3.80k | bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTextureType type) { |
80 | 3.80k | ai_assert(nullptr != pcMat); |
81 | | |
82 | 3.80k | unsigned int cur = 0, temp = 0; |
83 | 3.80k | aiString s; |
84 | 3.80k | bool ret = false; |
85 | | |
86 | 3.80k | for (const auto &texture : in) { |
87 | 522 | if (!texture.enabled || !texture.bCanUse) |
88 | 0 | continue; |
89 | 522 | ret = true; |
90 | | |
91 | | // Convert lightwave's mapping modes to ours. We let them |
92 | | // as they are, the GenUVcoords step will compute UV |
93 | | // channels if they're not there. |
94 | | |
95 | 522 | aiTextureMapping mapping = aiTextureMapping_OTHER; |
96 | 522 | switch (texture.mapMode) { |
97 | 10 | case LWO::Texture::Planar: |
98 | 10 | mapping = aiTextureMapping_PLANE; |
99 | 10 | break; |
100 | 6 | case LWO::Texture::Cylindrical: |
101 | 6 | mapping = aiTextureMapping_CYLINDER; |
102 | 6 | break; |
103 | 39 | case LWO::Texture::Spherical: |
104 | 39 | mapping = aiTextureMapping_SPHERE; |
105 | 39 | break; |
106 | 0 | case LWO::Texture::Cubic: |
107 | 0 | mapping = aiTextureMapping_BOX; |
108 | 0 | break; |
109 | 0 | case LWO::Texture::FrontProjection: |
110 | 0 | ASSIMP_LOG_ERROR("LWO2: Unsupported texture mapping: FrontProjection"); |
111 | 0 | mapping = aiTextureMapping_OTHER; |
112 | 0 | break; |
113 | 467 | case LWO::Texture::UV: { |
114 | 467 | if (UINT_MAX == texture.mRealUVIndex) { |
115 | | // We have no UV index for this texture, so we can't display it |
116 | 353 | continue; |
117 | 353 | } |
118 | | |
119 | | // add the UV source index |
120 | 114 | temp = texture.mRealUVIndex; |
121 | 114 | pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_UVWSRC(type, cur)); |
122 | | |
123 | 114 | mapping = aiTextureMapping_UV; |
124 | 114 | } break; |
125 | 0 | default: |
126 | 0 | ai_assert(false); |
127 | 522 | }; |
128 | | |
129 | 169 | if (mapping != aiTextureMapping_UV) { |
130 | | // Setup the main axis |
131 | 55 | aiVector3D v; |
132 | 55 | switch (texture.majorAxis) { |
133 | 7 | case Texture::AXIS_X: |
134 | 7 | v = aiVector3D(1.0, 0.0, 0.0); |
135 | 7 | break; |
136 | 14 | case Texture::AXIS_Y: |
137 | 14 | v = aiVector3D(0.0, 1.0, 0.0); |
138 | 14 | break; |
139 | 34 | default: // case Texture::AXIS_Z: |
140 | 34 | v = aiVector3D(0.0, 0.0, 1.0); |
141 | 34 | break; |
142 | 55 | } |
143 | | |
144 | 55 | pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS(type, cur)); |
145 | | |
146 | | // Setup UV scalings for cylindric and spherical projections |
147 | 55 | if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) { |
148 | 45 | aiUVTransform trafo; |
149 | 45 | trafo.mScaling.x = texture.wrapAmountW; |
150 | 45 | trafo.mScaling.y = texture.wrapAmountH; |
151 | | |
152 | 45 | static_assert(sizeof(aiUVTransform) / sizeof(ai_real) == 5, "sizeof(aiUVTransform)/sizeof(ai_real) == 5"); |
153 | 45 | pcMat->AddProperty(&trafo, 1, AI_MATKEY_UVTRANSFORM(type, cur)); |
154 | 45 | } |
155 | 55 | ASSIMP_LOG_VERBOSE_DEBUG("LWO2: Setting up non-UV mapping"); |
156 | 55 | } |
157 | | |
158 | | // The older LWOB format does not use indirect references to clips. |
159 | | // The file name of a texture is directly specified in the tex chunk. |
160 | 169 | if (mIsLWO2 || mIsLWO3) { |
161 | | // find the corresponding clip (take the last one if multiple |
162 | | // share the same index) |
163 | 169 | ClipList::iterator end = mClips.end(), candidate = end; |
164 | 169 | temp = texture.mClipIdx; |
165 | 338 | for (ClipList::iterator clip = mClips.begin(); clip != end; ++clip) { |
166 | 169 | if ((*clip).idx == temp) { |
167 | 169 | candidate = clip; |
168 | 169 | } |
169 | 169 | } |
170 | 169 | if (candidate == end) { |
171 | 0 | ASSIMP_LOG_ERROR("LWO2: Clip index is out of bounds"); |
172 | 0 | temp = 0; |
173 | | |
174 | | // fixme: apparently some LWO files shipping with Doom3 don't |
175 | | // have clips at all ... check whether that's true or whether |
176 | | // it's a bug in the loader. |
177 | |
|
178 | 0 | s.Set("$texture.png"); |
179 | | |
180 | | //continue; |
181 | 169 | } else { |
182 | 169 | if (Clip::UNSUPPORTED == (*candidate).type) { |
183 | 0 | ASSIMP_LOG_ERROR("LWO2: Clip type is not supported"); |
184 | 0 | continue; |
185 | 0 | } |
186 | 169 | AdjustTexturePath((*candidate).path); |
187 | 169 | s.Set((*candidate).path); |
188 | | |
189 | | // Additional image settings |
190 | 169 | int flags = 0; |
191 | 169 | if ((*candidate).negate) { |
192 | 0 | flags |= aiTextureFlags_Invert; |
193 | 0 | } |
194 | 169 | pcMat->AddProperty(&flags, 1, AI_MATKEY_TEXFLAGS(type, cur)); |
195 | 169 | } |
196 | 169 | } else { |
197 | 0 | std::string ss = texture.mFileName; |
198 | 0 | if (!ss.length()) { |
199 | 0 | ASSIMP_LOG_WARN("LWOB: Empty file name"); |
200 | 0 | continue; |
201 | 0 | } |
202 | 0 | AdjustTexturePath(ss); |
203 | 0 | s.Set(ss); |
204 | 0 | } |
205 | 169 | pcMat->AddProperty(&s, AI_MATKEY_TEXTURE(type, cur)); |
206 | | |
207 | | // add the blend factor |
208 | 169 | pcMat->AddProperty<float>(&texture.mStrength, 1, AI_MATKEY_TEXBLEND(type, cur)); |
209 | | |
210 | | // add the blend operation |
211 | 169 | switch (texture.blendType) { |
212 | 168 | case LWO::Texture::Normal: |
213 | 168 | case LWO::Texture::Multiply: |
214 | 168 | temp = (unsigned int)aiTextureOp_Multiply; |
215 | 168 | break; |
216 | | |
217 | 0 | case LWO::Texture::Subtractive: |
218 | 0 | case LWO::Texture::Difference: |
219 | 0 | temp = (unsigned int)aiTextureOp_Subtract; |
220 | 0 | break; |
221 | | |
222 | 0 | case LWO::Texture::Divide: |
223 | 0 | temp = (unsigned int)aiTextureOp_Divide; |
224 | 0 | break; |
225 | | |
226 | 0 | case LWO::Texture::Additive: |
227 | 0 | temp = (unsigned int)aiTextureOp_Add; |
228 | 0 | break; |
229 | | |
230 | 1 | default: |
231 | 1 | temp = (unsigned int)aiTextureOp_Multiply; |
232 | 1 | ASSIMP_LOG_WARN("LWO2: Unsupported texture blend mode: alpha or displacement"); |
233 | 169 | } |
234 | | // Setup texture operation |
235 | 169 | pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_TEXOP(type, cur)); |
236 | | |
237 | | // setup the mapping mode |
238 | 169 | int mapping_ = static_cast<int>(mapping); |
239 | 169 | pcMat->AddProperty<int>(&mapping_, 1, AI_MATKEY_MAPPING(type, cur)); |
240 | | |
241 | | // add the u-wrapping |
242 | 169 | temp = (unsigned int)GetMapMode(texture.wrapModeWidth); |
243 | 169 | pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_U(type, cur)); |
244 | | |
245 | | // add the v-wrapping |
246 | 169 | temp = (unsigned int)GetMapMode(texture.wrapModeHeight); |
247 | 169 | pcMat->AddProperty<int>((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_V(type, cur)); |
248 | | |
249 | 169 | ++cur; |
250 | 169 | } |
251 | 3.80k | return ret; |
252 | 3.80k | } |
253 | | |
254 | | // ------------------------------------------------------------------------------------------------ |
255 | 618 | void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) { |
256 | | // copy the name of the surface |
257 | 618 | aiString st; |
258 | 618 | st.Set(surf.mName); |
259 | 618 | pcMat->AddProperty(&st, AI_MATKEY_NAME); |
260 | | |
261 | 618 | const int i = surf.bDoubleSided ? 1 : 0; |
262 | 618 | pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); |
263 | | |
264 | | // add the refraction index and the bump intensity |
265 | 618 | pcMat->AddProperty(&surf.mIOR, 1, AI_MATKEY_REFRACTI); |
266 | 618 | pcMat->AddProperty(&surf.mBumpIntensity, 1, AI_MATKEY_BUMPSCALING); |
267 | | |
268 | 618 | aiShadingMode m; |
269 | 618 | if (surf.mSpecularValue && surf.mGlossiness) { |
270 | 6 | float fGloss; |
271 | 6 | if (mIsLWO2 || mIsLWO3) { |
272 | 6 | fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0)); |
273 | 6 | } else { |
274 | 0 | if (16.0 >= surf.mGlossiness) |
275 | 0 | fGloss = 6.0; |
276 | 0 | else if (64.0 >= surf.mGlossiness) |
277 | 0 | fGloss = 20.0; |
278 | 0 | else if (256.0 >= surf.mGlossiness) |
279 | 0 | fGloss = 50.0; |
280 | 0 | else |
281 | 0 | fGloss = 80.0; |
282 | 0 | } |
283 | | |
284 | 6 | pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH); |
285 | 6 | pcMat->AddProperty(&fGloss, 1, AI_MATKEY_SHININESS); |
286 | 6 | m = aiShadingMode_Phong; |
287 | 6 | } else |
288 | 612 | m = aiShadingMode_Gouraud; |
289 | | |
290 | | // specular color |
291 | 618 | aiColor3D clr = lerp(aiColor3D(1.0, 1.0, 1.0), surf.mColor, surf.mColorHighlights); |
292 | 618 | pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); |
293 | 618 | pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH); |
294 | | |
295 | | // emissive color |
296 | | // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good. |
297 | 618 | clr.g = clr.b = clr.r = surf.mLuminosity * ai_real(0.8); |
298 | 618 | pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_EMISSIVE); |
299 | | |
300 | | // opacity ... either additive or default-blended, please |
301 | 618 | if (0.0 != surf.mAdditiveTransparency) { |
302 | 0 | const int add = aiBlendMode_Additive; |
303 | 0 | pcMat->AddProperty(&surf.mAdditiveTransparency, 1, AI_MATKEY_OPACITY); |
304 | 0 | pcMat->AddProperty(&add, 1, AI_MATKEY_BLEND_FUNC); |
305 | 618 | } else if (10e10f != surf.mTransparency) { |
306 | 618 | const int def = aiBlendMode_Default; |
307 | 618 | const float f = 1.0f - surf.mTransparency; |
308 | 618 | pcMat->AddProperty(&f, 1, AI_MATKEY_OPACITY); |
309 | 618 | pcMat->AddProperty(&def, 1, AI_MATKEY_BLEND_FUNC); |
310 | 618 | } |
311 | | |
312 | | // ADD TEXTURES to the material |
313 | | // TODO: find out how we can handle COLOR textures correctly... |
314 | 618 | bool b = HandleTextures(pcMat, surf.mColorTextures, aiTextureType_DIFFUSE); |
315 | 618 | b = (b || HandleTextures(pcMat, surf.mDiffuseTextures, aiTextureType_DIFFUSE)); |
316 | 618 | HandleTextures(pcMat, surf.mSpecularTextures, aiTextureType_SPECULAR); |
317 | 618 | HandleTextures(pcMat, surf.mGlossinessTextures, aiTextureType_SHININESS); |
318 | 618 | HandleTextures(pcMat, surf.mBumpTextures, aiTextureType_HEIGHT); |
319 | 618 | HandleTextures(pcMat, surf.mOpacityTextures, aiTextureType_OPACITY); |
320 | 618 | HandleTextures(pcMat, surf.mReflectionTextures, aiTextureType_REFLECTION); |
321 | | |
322 | | // Now we need to know which shader to use .. iterate through the shader list of |
323 | | // the surface and search for a name which we know ... |
324 | 618 | for (const auto &shader : surf.mShaders) { |
325 | 0 | if (shader.functionName == "LW_SuperCelShader" || shader.functionName == "AH_CelShader") { |
326 | 0 | ASSIMP_LOG_INFO("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon"); |
327 | |
|
328 | 0 | m = aiShadingMode_Toon; |
329 | 0 | break; |
330 | 0 | } else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") { |
331 | 0 | ASSIMP_LOG_INFO("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel"); |
332 | |
|
333 | 0 | m = aiShadingMode_Fresnel; |
334 | 0 | break; |
335 | 0 | } else { |
336 | 0 | ASSIMP_LOG_WARN("LWO2: Unknown surface shader: ", shader.functionName); |
337 | 0 | } |
338 | 0 | } |
339 | 618 | if (surf.mMaximumSmoothAngle <= 0.0) |
340 | 601 | m = aiShadingMode_Flat; |
341 | 618 | int m_ = static_cast<int>(m); |
342 | 618 | pcMat->AddProperty(&m_, 1, AI_MATKEY_SHADING_MODEL); |
343 | | |
344 | | // (the diffuse value is just a scaling factor) |
345 | | // If a diffuse texture is set, we set this value to 1.0 |
346 | 618 | clr = (b ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor); |
347 | 618 | clr.r *= surf.mDiffuseValue; |
348 | 618 | clr.g *= surf.mDiffuseValue; |
349 | 618 | clr.b *= surf.mDiffuseValue; |
350 | 618 | pcMat->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); |
351 | 618 | } |
352 | | |
353 | | // ------------------------------------------------------------------------------------------------ |
354 | | char LWOImporter::FindUVChannels(LWO::TextureList &list, |
355 | 1.14k | LWO::Layer & /*layer*/, LWO::UVChannel &uv, unsigned int next) { |
356 | 1.14k | char ret = 0; |
357 | 1.14k | for (auto &texture : list) { |
358 | | |
359 | | // Ignore textures with non-UV mappings for the moment. |
360 | 142 | if (!texture.enabled || !texture.bCanUse || texture.mapMode != LWO::Texture::UV) { |
361 | 1 | continue; |
362 | 1 | } |
363 | | |
364 | 141 | if (texture.mUVChannelIndex == uv.name) { |
365 | 114 | ret = 1; |
366 | | |
367 | | // got it. |
368 | 114 | if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next) { |
369 | 114 | texture.mRealUVIndex = next; |
370 | 114 | } else { |
371 | | // channel mismatch. need to duplicate the material. |
372 | 0 | ASSIMP_LOG_WARN("LWO: Channel mismatch, would need to duplicate surface [design bug]"); |
373 | | |
374 | | // TODO |
375 | 0 | } |
376 | 114 | } |
377 | 141 | } |
378 | 1.14k | return ret; |
379 | 1.14k | } |
380 | | |
381 | | // ------------------------------------------------------------------------------------------------ |
382 | | void LWOImporter::FindUVChannels(LWO::Surface &surf, |
383 | | LWO::SortedRep &sorted, LWO::Layer &layer, |
384 | 415 | unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) { |
385 | 415 | unsigned int next = 0, extra = 0, num_extra = 0; |
386 | | |
387 | | // Check whether we have an UV entry != 0 for one of the faces in 'sorted' |
388 | 691 | for (unsigned int i = 0; i < layer.mUVChannels.size(); ++i) { |
389 | 276 | LWO::UVChannel &uv = layer.mUVChannels[i]; |
390 | | |
391 | 1.64k | for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { |
392 | | |
393 | 1.36k | LWO::Face &face = layer.mFaces[*it]; |
394 | | |
395 | 6.23k | for (unsigned int n = 0; n < face.mNumIndices; ++n) { |
396 | 5.03k | unsigned int idx = face.mIndices[n]; |
397 | | |
398 | 5.03k | if (uv.abAssigned[idx] && ((aiVector2D *)&uv.rawData[0])[idx] != aiVector2D()) { |
399 | | |
400 | 163 | if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
401 | |
|
402 | 0 | ASSIMP_LOG_ERROR("LWO: Maximum number of UV channels for " |
403 | 0 | "this mesh reached. Skipping channel \'" + |
404 | 0 | uv.name + "\'"); |
405 | |
|
406 | 163 | } else { |
407 | | // Search through all textures assigned to 'surf' and look for this UV channel |
408 | 163 | char had = 0; |
409 | 163 | had |= FindUVChannels(surf.mColorTextures, layer, uv, next); |
410 | 163 | had |= FindUVChannels(surf.mDiffuseTextures, layer, uv, next); |
411 | 163 | had |= FindUVChannels(surf.mSpecularTextures, layer, uv, next); |
412 | 163 | had |= FindUVChannels(surf.mGlossinessTextures, layer, uv, next); |
413 | 163 | had |= FindUVChannels(surf.mOpacityTextures, layer, uv, next); |
414 | 163 | had |= FindUVChannels(surf.mBumpTextures, layer, uv, next); |
415 | 163 | had |= FindUVChannels(surf.mReflectionTextures, layer, uv, next); |
416 | | |
417 | | // We have a texture referencing this UV channel so we have to take special care |
418 | | // and are willing to drop unreferenced channels in favour of it. |
419 | 163 | if (had != 0) { |
420 | 114 | if (num_extra) { |
421 | | |
422 | 4 | for (unsigned int a = next; a < std::min(extra, AI_MAX_NUMBER_OF_TEXTURECOORDS - 1u); ++a) { |
423 | 2 | out[a + 1] = out[a]; |
424 | 2 | } |
425 | 2 | } |
426 | 114 | ++extra; |
427 | 114 | out[next++] = i; |
428 | 114 | } |
429 | | // Bah ... seems not to be used at all. Push to end if enough space is available. |
430 | 49 | else { |
431 | 49 | out[extra++] = i; |
432 | 49 | ++num_extra; |
433 | 49 | } |
434 | 163 | } |
435 | 163 | it = sorted.end() - 1; |
436 | 163 | break; |
437 | 163 | } |
438 | 5.03k | } |
439 | 1.36k | } |
440 | 276 | } |
441 | 415 | if (extra < AI_MAX_NUMBER_OF_TEXTURECOORDS) { |
442 | 415 | out[extra] = UINT_MAX; |
443 | 415 | } |
444 | 415 | } |
445 | | |
446 | | // ------------------------------------------------------------------------------------------------ |
447 | | void LWOImporter::FindVCChannels(const LWO::Surface &surf, LWO::SortedRep &sorted, const LWO::Layer &layer, |
448 | 415 | unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]) { |
449 | 415 | unsigned int next = 0; |
450 | | |
451 | | // Check whether we have an vc entry != 0 for one of the faces in 'sorted' |
452 | 436 | for (unsigned int i = 0; i < layer.mVColorChannels.size(); ++i) { |
453 | 21 | const LWO::VColorChannel &vc = layer.mVColorChannels[i]; |
454 | | |
455 | 21 | if (surf.mVCMap == vc.name) { |
456 | | // The vertex color map is explicitly requested by the surface so we need to take special care of it |
457 | 9 | for (unsigned int a = 0; a < std::min(next, AI_MAX_NUMBER_OF_COLOR_SETS - 1u); ++a) { |
458 | 0 | out[a + 1] = out[a]; |
459 | 0 | } |
460 | 9 | out[0] = i; |
461 | 9 | ++next; |
462 | 12 | } else { |
463 | | |
464 | 429 | for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) { |
465 | 417 | const LWO::Face &face = layer.mFaces[*it]; |
466 | | |
467 | 1.98k | for (unsigned int n = 0; n < face.mNumIndices; ++n) { |
468 | 1.57k | unsigned int idx = face.mIndices[n]; |
469 | | |
470 | 1.57k | if (vc.abAssigned[idx] && ((aiColor4D *)&vc.rawData[0])[idx] != aiColor4D(0.0, 0.0, 0.0, 1.0)) { |
471 | 11 | if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) { |
472 | |
|
473 | 0 | ASSIMP_LOG_ERROR("LWO: Maximum number of vertex color channels for " |
474 | 0 | "this mesh reached. Skipping channel \'" + |
475 | 0 | vc.name + "\'"); |
476 | |
|
477 | 11 | } else { |
478 | 11 | out[next++] = i; |
479 | 11 | } |
480 | 11 | it = sorted.end() - 1; |
481 | 11 | break; |
482 | 11 | } |
483 | 1.57k | } |
484 | 417 | } |
485 | 12 | } |
486 | 21 | } |
487 | 415 | if (next != AI_MAX_NUMBER_OF_COLOR_SETS) { |
488 | 415 | out[next] = UINT_MAX; |
489 | 415 | } |
490 | 415 | } |
491 | | |
492 | | // ------------------------------------------------------------------------------------------------ |
493 | 803 | void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex) { |
494 | 803 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
495 | 8.72k | while (true) { |
496 | 8.72k | if (mFileBuffer + 6 >= end) break; |
497 | 7.93k | LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); |
498 | | |
499 | 7.93k | if (mFileBuffer + head.length > end) |
500 | 8 | throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length"); |
501 | | |
502 | 7.92k | uint8_t *const next = mFileBuffer + head.length; |
503 | 7.92k | switch (head.type) { |
504 | 798 | case AI_LWO_PROJ: |
505 | 798 | tex.mapMode = (Texture::MappingMode)GetU2(); |
506 | 798 | break; |
507 | 795 | case AI_LWO_WRAP: |
508 | 795 | tex.wrapModeWidth = (Texture::Wrap)GetU2(); |
509 | 795 | tex.wrapModeHeight = (Texture::Wrap)GetU2(); |
510 | 795 | break; |
511 | 797 | case AI_LWO_AXIS: |
512 | 797 | tex.majorAxis = (Texture::Axes)GetU2(); |
513 | 797 | break; |
514 | 797 | case AI_LWO_IMAG: |
515 | 797 | tex.mClipIdx = GetU2(); |
516 | 797 | break; |
517 | 740 | case AI_LWO_VMAP: |
518 | 740 | GetS0(tex.mUVChannelIndex, head.length); |
519 | 740 | break; |
520 | 790 | case AI_LWO_WRPH: |
521 | 790 | tex.wrapAmountH = GetF4(); |
522 | 790 | break; |
523 | 796 | case AI_LWO_WRPW: |
524 | 796 | tex.wrapAmountW = GetF4(); |
525 | 796 | break; |
526 | 7.92k | } |
527 | 7.92k | mFileBuffer = next; |
528 | 7.92k | } |
529 | 803 | } |
530 | | |
531 | | // ------------------------------------------------------------------------------------------------ |
532 | 0 | void LWOImporter::LoadLWO2Procedural(unsigned int /*size*/, LWO::Texture &tex) { |
533 | | // --- not supported at the moment |
534 | 0 | ASSIMP_LOG_ERROR("LWO2: Found procedural texture, this is not supported"); |
535 | 0 | tex.bCanUse = false; |
536 | 0 | } |
537 | | |
538 | | // ------------------------------------------------------------------------------------------------ |
539 | 0 | void LWOImporter::LoadLWO2Gradient(unsigned int /*size*/, LWO::Texture &tex) { |
540 | | // --- not supported at the moment |
541 | 0 | ASSIMP_LOG_ERROR("LWO2: Found gradient texture, this is not supported"); |
542 | 0 | tex.bCanUse = false; |
543 | 0 | } |
544 | | |
545 | | // ------------------------------------------------------------------------------------------------ |
546 | 807 | void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex) { |
547 | 807 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
548 | | |
549 | | // get the ordinal string |
550 | 807 | GetS0(tex.ordinal, size); |
551 | | |
552 | | // we could crash later if this is an empty string ... |
553 | 807 | if (!tex.ordinal.length()) { |
554 | 3 | ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string"); |
555 | 3 | tex.ordinal = "\x00"; |
556 | 3 | } |
557 | 4.01k | while (true) { |
558 | 4.01k | if (mFileBuffer + 6 >= end) break; |
559 | 3.21k | const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); |
560 | | |
561 | 3.21k | if (mFileBuffer + head.length > end) |
562 | 4 | throw DeadlyImportError("LWO2: Invalid texture header chunk length"); |
563 | | |
564 | 3.20k | uint8_t *const next = mFileBuffer + head.length; |
565 | 3.20k | switch (head.type) { |
566 | 801 | case AI_LWO_CHAN: |
567 | 801 | tex.type = GetU4(); |
568 | 801 | break; |
569 | 799 | case AI_LWO_ENAB: |
570 | 799 | tex.enabled = GetU2() ? true : false; |
571 | 799 | break; |
572 | 787 | case AI_LWO_OPAC: |
573 | 787 | tex.blendType = (Texture::BlendType)GetU2(); |
574 | 787 | tex.mStrength = GetF4(); |
575 | 787 | break; |
576 | 3.20k | } |
577 | 3.20k | mFileBuffer = next; |
578 | 3.20k | } |
579 | 807 | } |
580 | | |
581 | | // ------------------------------------------------------------------------------------------------ |
582 | 807 | void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head, unsigned int size) { |
583 | 807 | ai_assert(!mSurfaces->empty()); |
584 | 807 | LWO::Surface &surf = mSurfaces->back(); |
585 | 807 | LWO::Texture tex; |
586 | | |
587 | | // load the texture header |
588 | 807 | LoadLWO2TextureHeader(head->length, tex); |
589 | 807 | size -= head->length + 6; |
590 | | |
591 | | // now get the exact type of the texture |
592 | 807 | switch (head->type) { |
593 | 0 | case AI_LWO_PROC: |
594 | 0 | LoadLWO2Procedural(size, tex); |
595 | 0 | break; |
596 | 0 | case AI_LWO_GRAD: |
597 | 0 | LoadLWO2Gradient(size, tex); |
598 | 0 | break; |
599 | 803 | case AI_LWO_IMAP: |
600 | 803 | LoadLWO2ImageMap(size, tex); |
601 | 807 | } |
602 | | |
603 | | // get the destination channel |
604 | 795 | TextureList *listRef = nullptr; |
605 | 795 | switch (tex.type) { |
606 | 775 | case AI_LWO_COLR: |
607 | 775 | listRef = &surf.mColorTextures; |
608 | 775 | break; |
609 | 0 | case AI_LWO_DIFF: |
610 | 0 | listRef = &surf.mDiffuseTextures; |
611 | 0 | break; |
612 | 0 | case AI_LWO_SPEC: |
613 | 0 | listRef = &surf.mSpecularTextures; |
614 | 0 | break; |
615 | 0 | case AI_LWO_GLOS: |
616 | 0 | listRef = &surf.mGlossinessTextures; |
617 | 0 | break; |
618 | 0 | case AI_LWO_BUMP: |
619 | 0 | listRef = &surf.mBumpTextures; |
620 | 0 | break; |
621 | 0 | case AI_LWO_TRAN: |
622 | 0 | listRef = &surf.mOpacityTextures; |
623 | 0 | break; |
624 | 0 | case AI_LWO_REFL: |
625 | 0 | listRef = &surf.mReflectionTextures; |
626 | 0 | break; |
627 | 20 | default: |
628 | 20 | ASSIMP_LOG_WARN("LWO2: Encountered unknown texture type"); |
629 | 20 | return; |
630 | 795 | } |
631 | | |
632 | | // now attach the texture to the parent surface - sort by ordinal string |
633 | 775 | for (TextureList::iterator it = listRef->begin(); it != listRef->end(); ++it) { |
634 | 0 | if (::strcmp(tex.ordinal.c_str(), (*it).ordinal.c_str()) < 0) { |
635 | 0 | listRef->insert(it, tex); |
636 | 0 | return; |
637 | 0 | } |
638 | 0 | } |
639 | 775 | listRef->push_back(tex); |
640 | 775 | } |
641 | | |
642 | | // ------------------------------------------------------------------------------------------------ |
643 | 0 | void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader * /*head*/, unsigned int size) { |
644 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
645 | |
|
646 | 0 | ai_assert(!mSurfaces->empty()); |
647 | 0 | LWO::Surface &surf = mSurfaces->back(); |
648 | 0 | LWO::Shader shader; |
649 | | |
650 | | // get the ordinal string |
651 | 0 | GetS0(shader.ordinal, size); |
652 | | |
653 | | // we could crash later if this is an empty string ... |
654 | 0 | if (!shader.ordinal.length()) { |
655 | 0 | ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string"); |
656 | 0 | shader.ordinal = "\x00"; |
657 | 0 | } |
658 | | |
659 | | // read the header |
660 | 0 | while (true) { |
661 | 0 | if (mFileBuffer + 6 >= end) break; |
662 | 0 | const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); |
663 | |
|
664 | 0 | if (mFileBuffer + head.length > end) |
665 | 0 | throw DeadlyImportError("LWO2: Invalid shader header chunk length"); |
666 | | |
667 | 0 | uint8_t *const next = mFileBuffer + head.length; |
668 | 0 | switch (head.type) { |
669 | 0 | case AI_LWO_ENAB: |
670 | 0 | shader.enabled = GetU2() ? true : false; |
671 | 0 | break; |
672 | | |
673 | 0 | case AI_LWO_FUNC: |
674 | 0 | GetS0(shader.functionName, head.length); |
675 | 0 | } |
676 | 0 | mFileBuffer = next; |
677 | 0 | } |
678 | | |
679 | | // now attach the shader to the parent surface - sort by ordinal string |
680 | 0 | for (ShaderList::iterator it = surf.mShaders.begin(); it != surf.mShaders.end(); ++it) { |
681 | 0 | if (::strcmp(shader.ordinal.c_str(), (*it).ordinal.c_str()) < 0) { |
682 | 0 | surf.mShaders.insert(it, shader); |
683 | 0 | return; |
684 | 0 | } |
685 | 0 | } |
686 | 0 | surf.mShaders.push_back(shader); |
687 | 0 | } |
688 | | |
689 | | // ------------------------------------------------------------------------------------------------ |
690 | 0 | void LWOImporter::LoadNodalBlocks(unsigned int size) { |
691 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
692 | |
|
693 | 0 | while (true) { |
694 | 0 | if (mFileBuffer + 8 >= end) |
695 | 0 | break; |
696 | | |
697 | 0 | IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); |
698 | 0 | int bufOffset = 0; |
699 | 0 | if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form |
700 | 0 | mFileBuffer -= 8; |
701 | 0 | head = IFF::LoadForm(mFileBuffer); |
702 | 0 | bufOffset = 4; |
703 | 0 | } |
704 | |
|
705 | 0 | if (mFileBuffer + head.length > end) { |
706 | 0 | throw DeadlyImportError("LWO3: cannot read length; LoadNodalBlocks"); |
707 | 0 | } |
708 | 0 | uint8_t *const next = mFileBuffer + head.length; |
709 | 0 | mFileBuffer += bufOffset; |
710 | 0 | switch (head.type) { |
711 | 0 | case AI_LWO_NNDS: |
712 | 0 | LoadNodes(head.length); |
713 | 0 | break; |
714 | 0 | } |
715 | | |
716 | 0 | mFileBuffer = next; |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | | // ------------------------------------------------------------------------------------------------ |
721 | 0 | void LWOImporter::LoadNodes(unsigned int size) { |
722 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
723 | |
|
724 | 0 | while (true) { |
725 | 0 | if (mFileBuffer + 8 >= end) |
726 | 0 | break; |
727 | | |
728 | 0 | IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); |
729 | 0 | int bufOffset = 0; |
730 | 0 | if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form |
731 | 0 | mFileBuffer -= 8; |
732 | 0 | head = IFF::LoadForm(mFileBuffer); |
733 | 0 | bufOffset = 4; |
734 | 0 | } |
735 | |
|
736 | 0 | if (mFileBuffer + head.length > end) { |
737 | 0 | throw DeadlyImportError("LWO3: cannot read length; LoadNodes"); |
738 | 0 | } |
739 | | |
740 | 0 | uint8_t *const next = mFileBuffer + head.length; |
741 | 0 | mFileBuffer += bufOffset; |
742 | 0 | switch (head.type) { |
743 | 0 | case AI_LWO_NTAG: |
744 | 0 | LoadNodeTag(head.length); |
745 | 0 | break; |
746 | 0 | } |
747 | | |
748 | 0 | mFileBuffer = next; |
749 | 0 | } |
750 | 0 | } |
751 | | |
752 | | // ------------------------------------------------------------------------------------------------ |
753 | 0 | void LWOImporter::LoadNodeTag(unsigned int size) { |
754 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
755 | |
|
756 | 0 | while (true) { |
757 | 0 | if (mFileBuffer + 8 >= end) |
758 | 0 | break; |
759 | | |
760 | 0 | IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); |
761 | 0 | int bufOffset = 0; |
762 | 0 | if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form |
763 | 0 | mFileBuffer -= 8; |
764 | 0 | head = IFF::LoadForm(mFileBuffer); |
765 | 0 | bufOffset = 4; |
766 | 0 | } |
767 | |
|
768 | 0 | if (mFileBuffer + head.length > end) { |
769 | 0 | throw DeadlyImportError("LWO3: cannot read length; LoadNodeTag"); |
770 | 0 | } |
771 | | |
772 | 0 | uint8_t *const next = mFileBuffer + head.length; |
773 | 0 | mFileBuffer += bufOffset; |
774 | |
|
775 | 0 | switch (head.type) { |
776 | 0 | case AI_LWO_NDTA: |
777 | 0 | LoadNodeData(head.length); |
778 | 0 | break; |
779 | 0 | } |
780 | | |
781 | 0 | mFileBuffer = next; |
782 | 0 | } |
783 | 0 | } |
784 | | |
785 | | // ------------------------------------------------------------------------------------------------ |
786 | 0 | void LWOImporter::LoadNodeData(unsigned int size) { |
787 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
788 | |
|
789 | 0 | LWO::Surface &surf = mSurfaces->back(); |
790 | |
|
791 | 0 | while (true) { |
792 | 0 | if (mFileBuffer + 8 >= end) |
793 | 0 | break; |
794 | | |
795 | 0 | IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); |
796 | 0 | int bufOffset = 0; |
797 | 0 | if (head.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form |
798 | 0 | mFileBuffer -= 8; |
799 | 0 | head = IFF::LoadForm(mFileBuffer); |
800 | 0 | bufOffset = 4; |
801 | 0 | } |
802 | |
|
803 | 0 | if (mFileBuffer + head.length > end) { |
804 | 0 | throw DeadlyImportError("LWO3: INVALID LENGTH; LoadNodeData"); |
805 | 0 | } |
806 | | |
807 | 0 | uint8_t *const next = mFileBuffer + head.length; |
808 | 0 | mFileBuffer += bufOffset; |
809 | 0 | switch (head.type) { |
810 | 0 | case AI_LWO_VERS: |
811 | 0 | case AI_LWO_ENUM: |
812 | 0 | case AI_LWO_IBGC: |
813 | 0 | case AI_LWO_IOPC: |
814 | 0 | case AI_LWO_IIMG: |
815 | 0 | case AI_LWO_TXTR: |
816 | 0 | case AI_LWO_IFAL: |
817 | 0 | case AI_LWO_ISCL: |
818 | 0 | case AI_LWO_IPOS: |
819 | 0 | case AI_LWO_IROT: |
820 | 0 | case AI_LWO_IBMP: |
821 | 0 | case AI_LWO_IUTD: |
822 | 0 | case AI_LWO_IVTD: |
823 | |
|
824 | 0 | case AI_LWO_IPIX: |
825 | 0 | case AI_LWO_IMIP: |
826 | 0 | case AI_LWO_IMOD: |
827 | 0 | case AI_LWO_AMOD: |
828 | 0 | case AI_LWO_IINV: |
829 | 0 | case AI_LWO_INCR: |
830 | 0 | case AI_LWO_IAXS: |
831 | 0 | case AI_LWO_IFOT: |
832 | 0 | case AI_LWO_ITIM: |
833 | 0 | case AI_LWO_IWRL: |
834 | 0 | case AI_LWO_IUTI: |
835 | 0 | case AI_LWO_IUVI: |
836 | 0 | case AI_LWO_IINX: |
837 | 0 | case AI_LWO_IINY: |
838 | 0 | case AI_LWO_IINZ: |
839 | 0 | case AI_LWO_IREF: |
840 | 0 | case AI_LWO_IMST: |
841 | 0 | case AI_LWO_IMAP: |
842 | 0 | case AI_LWO_IUTL: |
843 | 0 | case AI_LWO_IVTL: |
844 | 0 | case AI_LWO_VPVL: |
845 | 0 | case AI_LWO_VPRM: |
846 | 0 | mFileBuffer = next; |
847 | 0 | break; |
848 | 0 | case AI_LWO_ENTR: |
849 | 0 | std::string attrName; |
850 | |
|
851 | 0 | while (true) { |
852 | 0 | if (mFileBuffer + 8 >= next) |
853 | 0 | break; |
854 | | |
855 | 0 | IFF::ChunkHeader head1 = IFF::LoadChunk(mFileBuffer); |
856 | 0 | int bufOffset1 = 0; |
857 | 0 | if (head1.type == AI_IFF_FOURCC_FORM) { // not chunk, it's a form |
858 | 0 | mFileBuffer -= 8; |
859 | 0 | head1 = IFF::LoadForm(mFileBuffer); |
860 | 0 | bufOffset1 = 4; |
861 | 0 | } |
862 | |
|
863 | 0 | if (mFileBuffer + head1.length > end) { |
864 | 0 | throw DeadlyImportError("LWO3: cannot read length;"); |
865 | 0 | } |
866 | 0 | uint8_t *const next1 = mFileBuffer + head1.length; |
867 | 0 | mFileBuffer += bufOffset1; |
868 | |
|
869 | 0 | switch (head1.type) { |
870 | 0 | case AI_LWO_FLAG: |
871 | 0 | case AI_LWO_TAG: |
872 | 0 | mFileBuffer = next1; |
873 | 0 | break; |
874 | 0 | case AI_LWO_NAME: |
875 | 0 | GetS0(attrName, head1.length); |
876 | 0 | break; |
877 | 0 | case AI_LWO_VALU: |
878 | 0 | mFileBuffer += 8; |
879 | |
|
880 | 0 | std::string valueType; |
881 | 0 | GetS0(valueType, 8); |
882 | |
|
883 | 0 | if (valueType == "int") { |
884 | 0 | static_cast<void>(GetU4()); |
885 | 0 | } else if (valueType == "double") { |
886 | 0 | static_cast<void>(GetU8()); |
887 | 0 | } else if (valueType == "vparam") { |
888 | 0 | mFileBuffer += 24; |
889 | |
|
890 | 0 | float value = GetF8(); |
891 | 0 | if (attrName == "Diffuse") { |
892 | 0 | surf.mDiffuseValue = value; |
893 | 0 | } else if (attrName == "Specular") { |
894 | 0 | surf.mSpecularValue = value; |
895 | 0 | } else if (attrName == "Transparency") { |
896 | 0 | surf.mTransparency = value; |
897 | 0 | } else if (attrName == "Glossiness") { |
898 | 0 | surf.mGlossiness = value; |
899 | 0 | } else if (attrName == "Luminosity") { |
900 | 0 | surf.mLuminosity = value; |
901 | 0 | } else if (attrName == "Color Highlight") { |
902 | 0 | surf.mColorHighlights = value; |
903 | 0 | } else if (attrName == "Refraction Index") { |
904 | 0 | surf.mIOR = value; |
905 | 0 | } else if (attrName == "Bump Height") { |
906 | 0 | surf.mBumpIntensity = value; |
907 | 0 | } |
908 | 0 | } else if (valueType == "vparam3") { |
909 | 0 | mFileBuffer += 24; |
910 | |
|
911 | 0 | float value1, value2, value3; |
912 | 0 | value1 = GetF8(); |
913 | 0 | value2 = GetF8(); |
914 | 0 | value3 = GetF8(); |
915 | |
|
916 | 0 | if (attrName == "Color") { |
917 | 0 | surf.mColor.r = value1; |
918 | 0 | surf.mColor.g = value2; |
919 | 0 | surf.mColor.b = value3; |
920 | 0 | } |
921 | 0 | } |
922 | |
|
923 | 0 | mFileBuffer = next1; |
924 | 0 | break; |
925 | 0 | } |
926 | 0 | } |
927 | | |
928 | 0 | break; |
929 | 0 | } |
930 | 0 | } |
931 | 0 | } |
932 | | |
933 | | // ------------------------------------------------------------------------------------------------ |
934 | 901 | void LWOImporter::LoadLWO2Surface(unsigned int size) { |
935 | 901 | LE_NCONST uint8_t *const end = mFileBuffer + size; |
936 | | |
937 | 901 | mSurfaces->push_back(LWO::Surface()); |
938 | 901 | LWO::Surface &surf = mSurfaces->back(); |
939 | | |
940 | 901 | GetS0(surf.mName, size); |
941 | | |
942 | | // check whether this surface was derived from any other surface |
943 | 901 | std::string derived; |
944 | 901 | GetS0(derived, (unsigned int)(end - mFileBuffer)); |
945 | 901 | if (derived.length()) { |
946 | | // yes, find this surface |
947 | 42 | for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) { |
948 | 27 | if ((*it).mName == derived) { |
949 | | // we have it ... |
950 | 0 | surf = *it; |
951 | 0 | derived.clear(); |
952 | 0 | break; |
953 | 0 | } |
954 | 27 | } |
955 | 15 | if (derived.size()) { |
956 | 15 | ASSIMP_LOG_WARN("LWO2: Unable to find source surface: ", derived); |
957 | 15 | } |
958 | 15 | } |
959 | | |
960 | 4.82k | while (true) { |
961 | 4.82k | if (mFileBuffer + 6 >= end) |
962 | 861 | break; |
963 | 3.96k | const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); |
964 | | |
965 | 3.96k | if (mFileBuffer + head.length > end) |
966 | 18 | throw DeadlyImportError("LWO2: Invalid surface chunk length"); |
967 | | |
968 | 3.94k | uint8_t *const next = mFileBuffer + head.length; |
969 | 3.94k | switch (head.type) { |
970 | | // diffuse color |
971 | 890 | case AI_LWO_COLR: { |
972 | 890 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, COLR, 12); |
973 | 887 | surf.mColor.r = GetF4(); |
974 | 887 | surf.mColor.g = GetF4(); |
975 | 887 | surf.mColor.b = GetF4(); |
976 | 887 | break; |
977 | 890 | } |
978 | | // diffuse strength ... hopefully |
979 | 881 | case AI_LWO_DIFF: { |
980 | 881 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, DIFF, 4); |
981 | 880 | surf.mDiffuseValue = GetF4(); |
982 | 880 | break; |
983 | 881 | } |
984 | | // specular strength ... hopefully |
985 | 785 | case AI_LWO_SPEC: { |
986 | 785 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPEC, 4); |
987 | 784 | surf.mSpecularValue = GetF4(); |
988 | 784 | break; |
989 | 785 | } |
990 | | // transparency |
991 | 10 | case AI_LWO_TRAN: { |
992 | | // transparency explicitly disabled? |
993 | 10 | if (surf.mTransparency == 10e10f) |
994 | 0 | break; |
995 | | |
996 | 10 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TRAN, 4); |
997 | 10 | surf.mTransparency = GetF4(); |
998 | 10 | break; |
999 | 10 | } |
1000 | | // additive transparency |
1001 | 6 | case AI_LWO_ADTR: { |
1002 | 6 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ADTR, 4); |
1003 | 5 | surf.mAdditiveTransparency = GetF4(); |
1004 | 5 | break; |
1005 | 6 | } |
1006 | | // wireframe mode |
1007 | 0 | case AI_LWO_LINE: { |
1008 | 0 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LINE, 2); |
1009 | 0 | if (GetU2() & 0x1) |
1010 | 0 | surf.mWireframe = true; |
1011 | 0 | break; |
1012 | 0 | } |
1013 | | // glossiness |
1014 | 7 | case AI_LWO_GLOS: { |
1015 | 7 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, GLOS, 4); |
1016 | 7 | surf.mGlossiness = GetF4(); |
1017 | 7 | break; |
1018 | 7 | } |
1019 | | // bump intensity |
1020 | 6 | case AI_LWO_BUMP: { |
1021 | 6 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BUMP, 4); |
1022 | 6 | surf.mBumpIntensity = GetF4(); |
1023 | 6 | break; |
1024 | 6 | } |
1025 | | // color highlights |
1026 | 0 | case AI_LWO_CLRH: { |
1027 | 0 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, CLRH, 4); |
1028 | 0 | surf.mColorHighlights = GetF4(); |
1029 | 0 | break; |
1030 | 0 | } |
1031 | | // index of refraction |
1032 | 10 | case AI_LWO_RIND: { |
1033 | 10 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, RIND, 4); |
1034 | 9 | surf.mIOR = GetF4(); |
1035 | 9 | break; |
1036 | 10 | } |
1037 | | // polygon sidedness |
1038 | 21 | case AI_LWO_SIDE: { |
1039 | 21 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2); |
1040 | 20 | surf.bDoubleSided = (3 == GetU2()); |
1041 | 20 | break; |
1042 | 21 | } |
1043 | | // maximum smoothing angle |
1044 | 33 | case AI_LWO_SMAN: { |
1045 | 33 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4); |
1046 | 32 | surf.mMaximumSmoothAngle = std::fabs(GetF4()); |
1047 | 32 | break; |
1048 | 33 | } |
1049 | | // vertex color channel to be applied to the surface |
1050 | 13 | case AI_LWO_VCOL: { |
1051 | 13 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, VCOL, 12); |
1052 | 13 | surf.mDiffuseValue *= GetF4(); // strength |
1053 | 13 | ReadVSizedIntLWO2(mFileBuffer); // skip envelope |
1054 | 13 | surf.mVCMapType = GetU4(); // type of the channel |
1055 | | |
1056 | | // name of the channel |
1057 | 13 | GetS0(surf.mVCMap, (unsigned int)(next - mFileBuffer)); |
1058 | 13 | break; |
1059 | 13 | } |
1060 | | // surface bock entry |
1061 | 815 | case AI_LWO_BLOK: { |
1062 | 815 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BLOK, 4); |
1063 | 814 | IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer); |
1064 | | |
1065 | 814 | switch (head2.type) { |
1066 | 0 | case AI_LWO_PROC: |
1067 | 0 | case AI_LWO_GRAD: |
1068 | 807 | case AI_LWO_IMAP: |
1069 | 807 | LoadLWO2TextureBlock(&head2, head.length); |
1070 | 807 | break; |
1071 | 0 | case AI_LWO_SHDR: |
1072 | 0 | LoadLWO2ShaderBlock(&head2, head.length); |
1073 | 0 | break; |
1074 | | |
1075 | 7 | default: |
1076 | 7 | ASSIMP_LOG_WARN("LWO2: Found an unsupported surface BLOK"); |
1077 | 814 | }; |
1078 | | |
1079 | 802 | break; |
1080 | 814 | } |
1081 | 3.94k | } |
1082 | 3.92k | mFileBuffer = next; |
1083 | 3.92k | } |
1084 | 901 | } |
1085 | | |
1086 | 0 | void LWOImporter::LoadLWO3Surface(unsigned int size) { |
1087 | 0 | mFileBuffer += 8; |
1088 | 0 | LE_NCONST uint8_t *const end = mFileBuffer + size - 12; |
1089 | |
|
1090 | 0 | mSurfaces->push_back(LWO::Surface()); |
1091 | 0 | LWO::Surface &surf = mSurfaces->back(); |
1092 | |
|
1093 | 0 | GetS0(surf.mName, size); |
1094 | | |
1095 | | // check whether this surface was derived from any other surface |
1096 | 0 | std::string derived; |
1097 | 0 | GetS0(derived, (unsigned int)(end - mFileBuffer)); |
1098 | 0 | if (derived.length()) { |
1099 | | // yes, find this surface |
1100 | 0 | for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) { |
1101 | 0 | if ((*it).mName == derived) { |
1102 | | // we have it ... |
1103 | 0 | surf = *it; |
1104 | 0 | derived.clear(); |
1105 | 0 | break; |
1106 | 0 | } |
1107 | 0 | } |
1108 | 0 | if (derived.size()) { |
1109 | 0 | ASSIMP_LOG_WARN("LWO3: Unable to find source surface: ", derived); |
1110 | 0 | } |
1111 | 0 | } |
1112 | 0 | while (true) { |
1113 | 0 | if (mFileBuffer + 8 >= end) |
1114 | 0 | break; |
1115 | | |
1116 | 0 | IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); |
1117 | 0 | int bufOffset = 0; |
1118 | 0 | if( head.type == AI_IFF_FOURCC_FORM ) { // not chunk, it's a form |
1119 | 0 | mFileBuffer -= 8; |
1120 | 0 | head = IFF::LoadForm(mFileBuffer); |
1121 | 0 | bufOffset = 4; |
1122 | 0 | } |
1123 | |
|
1124 | 0 | if (mFileBuffer + head.length > end) { |
1125 | 0 | throw DeadlyImportError("LWO3: cannot read length; LoadLWO3Surface"); |
1126 | 0 | } |
1127 | | |
1128 | 0 | uint8_t *const next = mFileBuffer + head.length; |
1129 | 0 | mFileBuffer += bufOffset; |
1130 | 0 | switch (head.type) { |
1131 | 0 | case AI_LWO_NODS: |
1132 | 0 | LoadNodalBlocks(head.length); |
1133 | 0 | break; |
1134 | | // polygon sidedness |
1135 | 0 | case AI_LWO_SIDE: { |
1136 | 0 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2); |
1137 | 0 | surf.bDoubleSided = (3 == GetU2()); |
1138 | 0 | break; |
1139 | 0 | } |
1140 | | // maximum smoothing angle |
1141 | 0 | case AI_LWO_SMAN: { |
1142 | 0 | AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4); |
1143 | 0 | surf.mMaximumSmoothAngle = std::fabs(GetF4()); |
1144 | 0 | break; |
1145 | 0 | } |
1146 | 0 | } |
1147 | 0 | mFileBuffer = next; |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | | #endif // ASSIMP_BUILD_NO_LWO_IMPORTER |