From f1fe73d1909a2448a004a88362a1a532d0d4f7c3 Mon Sep 17 00:00:00 2001 From: sanine Date: Sun, 12 Feb 2023 23:53:22 -0600 Subject: switch to tinyobj and nanovg from assimp and cairo --- libs/assimp/code/AssetLib/LWO/LWOAnimation.cpp | 609 ---------- libs/assimp/code/AssetLib/LWO/LWOAnimation.h | 346 ------ libs/assimp/code/AssetLib/LWO/LWOBLoader.cpp | 428 ------- libs/assimp/code/AssetLib/LWO/LWOFileData.h | 638 ----------- libs/assimp/code/AssetLib/LWO/LWOLoader.cpp | 1422 ------------------------ libs/assimp/code/AssetLib/LWO/LWOLoader.h | 468 -------- libs/assimp/code/AssetLib/LWO/LWOMaterial.cpp | 844 -------------- 7 files changed, 4755 deletions(-) delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOAnimation.cpp delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOAnimation.h delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOBLoader.cpp delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOFileData.h delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOLoader.cpp delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOLoader.h delete mode 100644 libs/assimp/code/AssetLib/LWO/LWOMaterial.cpp (limited to 'libs/assimp/code/AssetLib/LWO') diff --git a/libs/assimp/code/AssetLib/LWO/LWOAnimation.cpp b/libs/assimp/code/AssetLib/LWO/LWOAnimation.cpp deleted file mode 100644 index c2ee2d9..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOAnimation.cpp +++ /dev/null @@ -1,609 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file LWOAnimation.cpp - * @brief LWOAnimationResolver utility class - * - * It's a very generic implementation of LightWave's system of - * component-wise-animated stuff. The one and only fully free - * implementation of LightWave envelopes of which I know. -*/ - -#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) && (!defined ASSIMP_BUILD_NO_LWS_IMPORTER) - -#include - -// internal headers -#include "LWOFileData.h" -#include - -using namespace Assimp; -using namespace Assimp::LWO; - -// ------------------------------------------------------------------------------------------------ -// Construct an animation resolver from a given list of envelopes -AnimResolver::AnimResolver(std::list &_envelopes, double tick) : - envelopes(_envelopes), - sample_rate(0.), - envl_x(), - envl_y(), - envl_z(), - end_x(), - end_y(), - end_z(), - flags(), - sample_delta() { - trans_x = trans_y = trans_z = nullptr; - rotat_x = rotat_y = rotat_z = nullptr; - scale_x = scale_y = scale_z = nullptr; - - first = last = 150392.; - - // find transformation envelopes - for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { - - (*it).old_first = 0; - (*it).old_last = (*it).keys.size() - 1; - - if ((*it).keys.empty()) { - continue; - } - if ((int)(*it).type < 1 || (int)(*it).type>EnvelopeType_Unknown) { - continue; - } - switch ((*it).type) { - // translation - case LWO::EnvelopeType_Position_X: - trans_x = &*it; - break; - case LWO::EnvelopeType_Position_Y: - trans_y = &*it; - break; - case LWO::EnvelopeType_Position_Z: - trans_z = &*it; - break; - - // rotation - case LWO::EnvelopeType_Rotation_Heading: - rotat_x = &*it; - break; - case LWO::EnvelopeType_Rotation_Pitch: - rotat_y = &*it; - break; - case LWO::EnvelopeType_Rotation_Bank: - rotat_z = &*it; - break; - - // scaling - case LWO::EnvelopeType_Scaling_X: - scale_x = &*it; - break; - case LWO::EnvelopeType_Scaling_Y: - scale_y = &*it; - break; - case LWO::EnvelopeType_Scaling_Z: - scale_z = &*it; - break; - default: - continue; - }; - - // convert from seconds to ticks - for (std::vector::iterator d = (*it).keys.begin(); d != (*it).keys.end(); ++d) - (*d).time *= tick; - - // set default animation range (minimum and maximum time value for which we have a keyframe) - first = std::min(first, (*it).keys.front().time); - last = std::max(last, (*it).keys.back().time); - } - - // deferred setup of animation range to increase performance. - // typically the application will want to specify its own. - need_to_setup = true; -} - -// ------------------------------------------------------------------------------------------------ -// Reset all envelopes to their original contents -void AnimResolver::ClearAnimRangeSetup() { - for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { - - (*it).keys.erase((*it).keys.begin(), (*it).keys.begin() + (*it).old_first); - (*it).keys.erase((*it).keys.begin() + (*it).old_last + 1, (*it).keys.end()); - } -} - -// ------------------------------------------------------------------------------------------------ -// Insert additional keys to match LWO's pre& post behaviors. -void AnimResolver::UpdateAnimRangeSetup() { - // XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated) - - for (std::list::iterator it = envelopes.begin(); it != envelopes.end(); ++it) { - if ((*it).keys.empty()) continue; - - const double my_first = (*it).keys.front().time; - const double my_last = (*it).keys.back().time; - - const double delta = my_last - my_first; - const size_t old_size = (*it).keys.size(); - - const float value_delta = (*it).keys.back().value - (*it).keys.front().value; - - // NOTE: We won't handle reset, linear and constant here. - // See DoInterpolation() for their implementation. - - // process pre behavior - switch ((*it).pre) { - case LWO::PrePostBehaviour_OffsetRepeat: - case LWO::PrePostBehaviour_Repeat: - case LWO::PrePostBehaviour_Oscillate: { - const double start_time = delta - std::fmod(my_first - first, delta); - std::vector::iterator n = std::find_if((*it).keys.begin(), (*it).keys.end(), - [start_time](double t) { return start_time > t; }), - m; - - size_t ofs = 0; - if (n != (*it).keys.end()) { - // copy from here - don't use iterators, insert() would invalidate them - ofs = (*it).keys.end() - n; - (*it).keys.insert((*it).keys.begin(), ofs, LWO::Key()); - - std::copy((*it).keys.end() - ofs, (*it).keys.end(), (*it).keys.begin()); - } - - // do full copies. again, no iterators - const unsigned int num = (unsigned int)((my_first - first) / delta); - (*it).keys.resize((*it).keys.size() + num * old_size); - - n = (*it).keys.begin() + ofs; - bool reverse = false; - for (unsigned int i = 0; i < num; ++i) { - m = n + old_size * (i + 1); - std::copy(n, n + old_size, m); - const bool res = ((*it).pre == LWO::PrePostBehaviour_Oscillate); - reverse = !reverse; - if (res && reverse) { - std::reverse(m, m + old_size - 1); - } - } - - // update time values - n = (*it).keys.end() - (old_size + 1); - double cur_minus = delta; - unsigned int tt = 1; - for (const double tmp = delta * (num + 1); cur_minus <= tmp; cur_minus += delta, ++tt) { - m = (delta == tmp ? (*it).keys.begin() : n - (old_size + 1)); - for (; m != n; --n) { - (*n).time -= cur_minus; - - // offset repeat? add delta offset to key value - if ((*it).pre == LWO::PrePostBehaviour_OffsetRepeat) { - (*n).value += tt * value_delta; - } - } - } - break; - } - default: - // silence compiler warning - break; - } - - // process post behavior - switch ((*it).post) { - - case LWO::PrePostBehaviour_OffsetRepeat: - case LWO::PrePostBehaviour_Repeat: - case LWO::PrePostBehaviour_Oscillate: - - break; - - default: - // silence compiler warning - break; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Extract bind pose matrix -void AnimResolver::ExtractBindPose(aiMatrix4x4 &out) { - // If we have no envelopes, return identity - if (envelopes.empty()) { - out = aiMatrix4x4(); - return; - } - aiVector3D angles, scaling(1.f, 1.f, 1.f), translation; - - if (trans_x) translation.x = trans_x->keys[0].value; - if (trans_y) translation.y = trans_y->keys[0].value; - if (trans_z) translation.z = trans_z->keys[0].value; - - if (rotat_x) angles.x = rotat_x->keys[0].value; - if (rotat_y) angles.y = rotat_y->keys[0].value; - if (rotat_z) angles.z = rotat_z->keys[0].value; - - if (scale_x) scaling.x = scale_x->keys[0].value; - if (scale_y) scaling.y = scale_y->keys[0].value; - if (scale_z) scaling.z = scale_z->keys[0].value; - - // build the final matrix - aiMatrix4x4 s, rx, ry, rz, t; - aiMatrix4x4::RotationZ(angles.z, rz); - aiMatrix4x4::RotationX(angles.y, rx); - aiMatrix4x4::RotationY(angles.x, ry); - aiMatrix4x4::Translation(translation, t); - aiMatrix4x4::Scaling(scaling, s); - out = t * ry * rx * rz * s; -} - -// ------------------------------------------------------------------------------------------------ -// Do a single interpolation on a channel -void AnimResolver::DoInterpolation(std::vector::const_iterator cur, - LWO::Envelope *envl, double time, float &fill) { - if (envl->keys.size() == 1) { - fill = envl->keys[0].value; - return; - } - - // check whether we're at the beginning of the animation track - if (cur == envl->keys.begin()) { - - // ok ... this depends on pre behaviour now - // we don't need to handle repeat&offset repeat&oszillate here, see UpdateAnimRangeSetup() - switch (envl->pre) { - case LWO::PrePostBehaviour_Linear: - DoInterpolation2(cur, cur + 1, time, fill); - return; - - case LWO::PrePostBehaviour_Reset: - fill = 0.f; - return; - - default: //case LWO::PrePostBehaviour_Constant: - fill = (*cur).value; - return; - } - } - // check whether we're at the end of the animation track - else if (cur == envl->keys.end() - 1 && time > envl->keys.rbegin()->time) { - // ok ... this depends on post behaviour now - switch (envl->post) { - case LWO::PrePostBehaviour_Linear: - DoInterpolation2(cur, cur - 1, time, fill); - return; - - case LWO::PrePostBehaviour_Reset: - fill = 0.f; - return; - - default: //case LWO::PrePostBehaviour_Constant: - fill = (*cur).value; - return; - } - } - - // Otherwise do a simple interpolation - DoInterpolation2(cur - 1, cur, time, fill); -} - -// ------------------------------------------------------------------------------------------------ -// Almost the same, except we won't handle pre/post conditions here -void AnimResolver::DoInterpolation2(std::vector::const_iterator beg, - std::vector::const_iterator end, double time, float &fill) { - switch ((*end).inter) { - - case LWO::IT_STEP: - // no interpolation at all - take the value of the last key - fill = (*beg).value; - return; - default: - - // silence compiler warning - break; - } - // linear interpolation - default - double duration = (*end).time - (*beg).time; - if (duration > 0.0) { - fill = (*beg).value + ((*end).value - (*beg).value) * (float)(((time - (*beg).time) / duration)); - } else { - fill = (*beg).value; - } -} - -// ------------------------------------------------------------------------------------------------ -// Subsample animation track by given key values -void AnimResolver::SubsampleAnimTrack(std::vector & /*out*/, - double /*time*/, double /*sample_delta*/) { - //ai_assert(out.empty() && sample_delta); - - //const double time_start = out.back().mTime; - // for () -} - -// ------------------------------------------------------------------------------------------------ -// Track interpolation -void AnimResolver::InterpolateTrack(std::vector &out, aiVectorKey &fill, double time) { - // subsample animation track? - if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { - SubsampleAnimTrack(out, time, sample_delta); - } - - fill.mTime = time; - - // get x - if ((*cur_x).time == time) { - fill.mValue.x = (*cur_x).value; - - if (cur_x != envl_x->keys.end() - 1) /* increment x */ - ++cur_x; - else - end_x = true; - } else - DoInterpolation(cur_x, envl_x, time, (float &)fill.mValue.x); - - // get y - if ((*cur_y).time == time) { - fill.mValue.y = (*cur_y).value; - - if (cur_y != envl_y->keys.end() - 1) /* increment y */ - ++cur_y; - else - end_y = true; - } else - DoInterpolation(cur_y, envl_y, time, (float &)fill.mValue.y); - - // get z - if ((*cur_z).time == time) { - fill.mValue.z = (*cur_z).value; - - if (cur_z != envl_z->keys.end() - 1) /* increment z */ - ++cur_z; - else - end_x = true; - } else - DoInterpolation(cur_z, envl_z, time, (float &)fill.mValue.z); -} - -// ------------------------------------------------------------------------------------------------ -// Build linearly subsampled keys from three single envelopes, one for each component (x,y,z) -void AnimResolver::GetKeys(std::vector &out, - LWO::Envelope *_envl_x, - LWO::Envelope *_envl_y, - LWO::Envelope *_envl_z, - unsigned int _flags) { - envl_x = _envl_x; - envl_y = _envl_y; - envl_z = _envl_z; - flags = _flags; - - // generate default channels if none are given - LWO::Envelope def_x, def_y, def_z; - LWO::Key key_dummy; - key_dummy.time = 0.f; - if ((envl_x && envl_x->type == LWO::EnvelopeType_Scaling_X) || - (envl_y && envl_y->type == LWO::EnvelopeType_Scaling_Y) || - (envl_z && envl_z->type == LWO::EnvelopeType_Scaling_Z)) { - key_dummy.value = 1.f; - } else - key_dummy.value = 0.f; - - if (!envl_x) { - envl_x = &def_x; - envl_x->keys.push_back(key_dummy); - } - if (!envl_y) { - envl_y = &def_y; - envl_y->keys.push_back(key_dummy); - } - if (!envl_z) { - envl_z = &def_z; - envl_z->keys.push_back(key_dummy); - } - - // guess how many keys we'll get - size_t reserve; - double sr = 1.; - if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { - if (!sample_rate) - sr = 100.f; - else - sr = sample_rate; - sample_delta = 1.f / sr; - - reserve = (size_t)( - std::max(envl_x->keys.rbegin()->time, - std::max(envl_y->keys.rbegin()->time, envl_z->keys.rbegin()->time)) * - sr); - } else - reserve = std::max(envl_x->keys.size(), std::max(envl_x->keys.size(), envl_z->keys.size())); - out.reserve(reserve + (reserve >> 1)); - - // Iterate through all three arrays at once - it's tricky, but - // rather interesting to implement. - cur_x = envl_x->keys.begin(); - cur_y = envl_y->keys.begin(); - cur_z = envl_z->keys.begin(); - - end_x = end_y = end_z = false; - while (1) { - - aiVectorKey fill; - - if ((*cur_x).time == (*cur_y).time && (*cur_x).time == (*cur_z).time) { - - // we have a keyframe for all of them defined .. this means - // we don't need to interpolate here. - fill.mTime = (*cur_x).time; - - fill.mValue.x = (*cur_x).value; - fill.mValue.y = (*cur_y).value; - fill.mValue.z = (*cur_z).value; - - // subsample animation track - if (flags & AI_LWO_ANIM_FLAG_SAMPLE_ANIMS) { - //SubsampleAnimTrack(out,cur_x, cur_y, cur_z, d, sample_delta); - } - } - - // Find key with lowest time value - else if ((*cur_x).time <= (*cur_y).time && !end_x) { - - if ((*cur_z).time <= (*cur_x).time && !end_z) { - InterpolateTrack(out, fill, (*cur_z).time); - } else { - InterpolateTrack(out, fill, (*cur_x).time); - } - } else if ((*cur_z).time <= (*cur_y).time && !end_y) { - InterpolateTrack(out, fill, (*cur_y).time); - } else if (!end_y) { - // welcome on the server, y - InterpolateTrack(out, fill, (*cur_y).time); - } else { - // we have reached the end of at least 2 channels, - // only one is remaining. Extrapolate the 2. - if (end_y) { - InterpolateTrack(out, fill, (end_x ? (*cur_z) : (*cur_x)).time); - } else if (end_x) { - InterpolateTrack(out, fill, (end_z ? (*cur_y) : (*cur_z)).time); - } else { // if (end_z) - InterpolateTrack(out, fill, (end_y ? (*cur_x) : (*cur_y)).time); - } - } - double lasttime = fill.mTime; - out.push_back(fill); - - if (lasttime >= (*cur_x).time) { - if (cur_x != envl_x->keys.end() - 1) - ++cur_x; - else - end_x = true; - } - if (lasttime >= (*cur_y).time) { - if (cur_y != envl_y->keys.end() - 1) - ++cur_y; - else - end_y = true; - } - if (lasttime >= (*cur_z).time) { - if (cur_z != envl_z->keys.end() - 1) - ++cur_z; - else - end_z = true; - } - - if (end_x && end_y && end_z) /* finished? */ - break; - } - - if (flags & AI_LWO_ANIM_FLAG_START_AT_ZERO) { - for (std::vector::iterator it = out.begin(); it != out.end(); ++it) - (*it).mTime -= first; - } -} - -// ------------------------------------------------------------------------------------------------ -// Extract animation channel -void AnimResolver::ExtractAnimChannel(aiNodeAnim **out, unsigned int /*= 0*/) { - *out = nullptr; - - //FIXME: crashes if more than one component is animated at different timings, to be resolved. - - // If we have no envelopes, return nullptr - if (envelopes.empty()) { - return; - } - - // We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined. - const bool trans = ((trans_x && trans_x->keys.size() > 1) || (trans_y && trans_y->keys.size() > 1) || (trans_z && trans_z->keys.size() > 1)); - const bool rotat = ((rotat_x && rotat_x->keys.size() > 1) || (rotat_y && rotat_y->keys.size() > 1) || (rotat_z && rotat_z->keys.size() > 1)); - const bool scale = ((scale_x && scale_x->keys.size() > 1) || (scale_y && scale_y->keys.size() > 1) || (scale_z && scale_z->keys.size() > 1)); - if (!trans && !rotat && !scale) - return; - - // Allocate the output animation - aiNodeAnim *anim = *out = new aiNodeAnim(); - - // Setup default animation setup if necessary - if (need_to_setup) { - UpdateAnimRangeSetup(); - need_to_setup = false; - } - - // copy translation keys - if (trans) { - std::vector keys; - GetKeys(keys, trans_x, trans_y, trans_z, flags); - - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = static_cast(keys.size())]; - std::copy(keys.begin(), keys.end(), anim->mPositionKeys); - } - - // copy rotation keys - if (rotat) { - std::vector keys; - GetKeys(keys, rotat_x, rotat_y, rotat_z, flags); - - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = static_cast(keys.size())]; - - // convert heading, pitch, bank to quaternion - // mValue.x=Heading=Rot(Y), mValue.y=Pitch=Rot(X), mValue.z=Bank=Rot(Z) - // Lightwave's rotation order is ZXY - aiVector3D X(1.0, 0.0, 0.0); - aiVector3D Y(0.0, 1.0, 0.0); - aiVector3D Z(0.0, 0.0, 1.0); - for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { - aiQuatKey &qk = anim->mRotationKeys[i]; - qk.mTime = keys[i].mTime; - qk.mValue = aiQuaternion(Y, keys[i].mValue.x) * aiQuaternion(X, keys[i].mValue.y) * aiQuaternion(Z, keys[i].mValue.z); - } - } - - // copy scaling keys - if (scale) { - std::vector keys; - GetKeys(keys, scale_x, scale_y, scale_z, flags); - - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = static_cast(keys.size())]; - std::copy(keys.begin(), keys.end(), anim->mScalingKeys); - } -} - -#endif // no lwo or no lws diff --git a/libs/assimp/code/AssetLib/LWO/LWOAnimation.h b/libs/assimp/code/AssetLib/LWO/LWOAnimation.h deleted file mode 100644 index 1e419d4..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOAnimation.h +++ /dev/null @@ -1,346 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file LWOAnimation.h - * @brief LWOAnimationResolver utility class - * - * This is for all lightwave-related file format, not only LWO. - * LWS isthe main purpose. -*/ -#ifndef AI_LWO_ANIMATION_INCLUDED -#define AI_LWO_ANIMATION_INCLUDED - -// -#include -#include - -struct aiNodeAnim; -struct aiVectorKey; - -namespace Assimp { -namespace LWO { - -// --------------------------------------------------------------------------- -/** \brief List of recognized LWO envelopes - */ -enum EnvelopeType -{ - EnvelopeType_Position_X = 0x1, - EnvelopeType_Position_Y = 0x2, - EnvelopeType_Position_Z = 0x3, - - EnvelopeType_Rotation_Heading = 0x4, - EnvelopeType_Rotation_Pitch = 0x5, - EnvelopeType_Rotation_Bank = 0x6, - - EnvelopeType_Scaling_X = 0x7, - EnvelopeType_Scaling_Y = 0x8, - EnvelopeType_Scaling_Z = 0x9, - - // -- currently not yet handled - EnvelopeType_Color_R = 0xa, - EnvelopeType_Color_G = 0xb, - EnvelopeType_Color_B = 0xc, - - EnvelopeType_Falloff_X = 0xd, - EnvelopeType_Falloff_Y = 0xe, - EnvelopeType_Falloff_Z = 0xf, - - EnvelopeType_Unknown -}; - -// --------------------------------------------------------------------------- -/** \brief List of recognized LWO interpolation modes - */ -enum InterpolationType -{ - IT_STEP, IT_LINE, IT_TCB, IT_HERM, IT_BEZI, IT_BEZ2 -}; - - -// --------------------------------------------------------------------------- -/** \brief List of recognized LWO pre or post range behaviours - */ -enum PrePostBehaviour -{ - PrePostBehaviour_Reset = 0x0, - PrePostBehaviour_Constant = 0x1, - PrePostBehaviour_Repeat = 0x2, - PrePostBehaviour_Oscillate = 0x3, - PrePostBehaviour_OffsetRepeat = 0x4, - PrePostBehaviour_Linear = 0x5 -}; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO animation keyframe - */ -struct Key { - Key() AI_NO_EXCEPT - : time() - , value() - , inter(IT_LINE) - , params() { - // empty - } - - //! Current time - double time; - - //! Current value - float value; - - //! How to interpolate this key with previous key? - InterpolationType inter; - - //! Interpolation parameters - float params[5]; - - - // for std::find() - operator double () { - return time; - } -}; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO animation envelope - */ -struct Envelope { - Envelope() AI_NO_EXCEPT - : index() - , type(EnvelopeType_Unknown) - , pre(PrePostBehaviour_Constant) - , post(PrePostBehaviour_Constant) - , old_first(0) - , old_last(0) { - // empty - } - - //! Index of this envelope - unsigned int index; - - //! Type of envelope - EnvelopeType type; - - //! Pre- and post-behavior - PrePostBehaviour pre,post; - - //! Keyframes for this envelope - std::vector keys; - - // temporary data for AnimResolver - size_t old_first,old_last; -}; - -// --------------------------------------------------------------------------- -//! @def AI_LWO_ANIM_FLAG_SAMPLE_ANIMS -//! Flag for AnimResolver, subsamples the input data with the rate specified -//! by AnimResolver::SetSampleRate(). -#define AI_LWO_ANIM_FLAG_SAMPLE_ANIMS 0x1 - - -// --------------------------------------------------------------------------- -//! @def AI_LWO_ANIM_FLAG_START_AT_ZERO -//! Flag for AnimResolver, ensures that the animations starts at zero. -#define AI_LWO_ANIM_FLAG_START_AT_ZERO 0x2 - -// --------------------------------------------------------------------------- -/** @brief Utility class to build Assimp animations from LWO envelopes. - * - * Used for both LWO and LWS (MOT also). - */ -class AnimResolver -{ -public: - - // ------------------------------------------------------------------ - /** @brief Construct an AnimResolver from a given list of envelopes - * @param envelopes Input envelopes. May be empty. - * @param Output tick rate, per second - * @note The input envelopes are possibly modified. - */ - AnimResolver(std::list& envelopes, double tick); - -public: - - // ------------------------------------------------------------------ - /** @brief Extract the bind-pose transformation matrix. - * @param out Receives bind-pose transformation matrix - */ - void ExtractBindPose(aiMatrix4x4& out); - - // ------------------------------------------------------------------ - /** @brief Extract a node animation channel - * @param out Receives a pointer to a newly allocated node anim. - * If there's just one keyframe defined, *out is set to nullptr and - * no animation channel is computed. - * @param flags Any combination of the AI_LWO_ANIM_FLAG_XXX flags. - */ - void ExtractAnimChannel(aiNodeAnim** out, unsigned int flags = 0); - - - // ------------------------------------------------------------------ - /** @brief Set the sampling rate for ExtractAnimChannel(). - * - * Non-linear interpolations are subsampled with this rate (keys - * per second). Closer sampling positions, if existent, are kept. - * The sampling rate defaults to 0, if this value is not changed and - * AI_LWO_ANIM_FLAG_SAMPLE_ANIMS is specified for ExtractAnimChannel(), - * the class finds a suitable sample rate by itself. - */ - void SetSampleRate(double sr) { - sample_rate = sr; - } - - // ------------------------------------------------------------------ - /** @brief Getter for SetSampleRate() - */ - double GetSampleRate() const { - return sample_rate; - } - - // ------------------------------------------------------------------ - /** @brief Set the animation time range - * - * @param first Time where the animation starts, in ticks - * @param last Time where the animation ends, in ticks - */ - void SetAnimationRange(double _first, double _last) { - first = _first; - last = _last; - - ClearAnimRangeSetup(); - UpdateAnimRangeSetup(); - } - -protected: - - // ------------------------------------------------------------------ - /** @brief Build linearly subsampled keys from 3 single envelopes - * @param out Receives output keys - * @param envl_x X-component envelope - * @param envl_y Y-component envelope - * @param envl_z Z-component envelope - * @param flags Any combination of the AI_LWO_ANIM_FLAG_XXX flags. - * @note Up to two input envelopes may be nullptr - */ - void GetKeys(std::vector& out, - LWO::Envelope* envl_x, - LWO::Envelope* envl_y, - LWO::Envelope* envl_z, - unsigned int flags); - - // ------------------------------------------------------------------ - /** @brief Resolve a single animation key by applying the right - * interpolation to it. - * @param cur Current key - * @param envl Envelope working on - * @param time time to be interpolated - * @param fill Receives the interpolated output value. - */ - void DoInterpolation(std::vector::const_iterator cur, - LWO::Envelope* envl,double time, float& fill); - - // ------------------------------------------------------------------ - /** @brief Almost the same, except we won't handle pre/post - * conditions here. - * @see DoInterpolation - */ - void DoInterpolation2(std::vector::const_iterator beg, - std::vector::const_iterator end,double time, float& fill); - - // ------------------------------------------------------------------ - /** @brief Interpolate 2 tracks if one is given - * - * @param out Receives extra output keys - * @param key_out Primary output key - * @param time Time to interpolate for - */ - void InterpolateTrack(std::vector& out, - aiVectorKey& key_out,double time); - - // ------------------------------------------------------------------ - /** @brief Subsample an animation track by a given sampling rate - * - * @param out Receives output keys. Last key at input defines the - * time where subsampling starts. - * @param time Time to end subsampling at - * @param sample_delta Time delta between two samples - */ - void SubsampleAnimTrack(std::vector& out, - double time,double sample_delta); - - // ------------------------------------------------------------------ - /** @brief Delete all keys which we inserted to match anim setup - */ - void ClearAnimRangeSetup(); - - // ------------------------------------------------------------------ - /** @brief Insert extra keys to match LWO's pre and post behaviours - * in a given time range [first...last] - */ - void UpdateAnimRangeSetup(); - -private: - std::list& envelopes; - double sample_rate; - - LWO::Envelope* trans_x, *trans_y, *trans_z; - LWO::Envelope* rotat_x, *rotat_y, *rotat_z; - LWO::Envelope* scale_x, *scale_y, *scale_z; - - double first, last; - bool need_to_setup; - - // temporary storage - LWO::Envelope* envl_x, * envl_y, * envl_z; - std::vector::const_iterator cur_x,cur_y,cur_z; - bool end_x, end_y, end_z; - - unsigned int flags; - double sample_delta; -}; - -} // end namespace LWO -} // end namespace Assimp - -#endif // !! AI_LWO_ANIMATION_INCLUDED diff --git a/libs/assimp/code/AssetLib/LWO/LWOBLoader.cpp b/libs/assimp/code/AssetLib/LWO/LWOBLoader.cpp deleted file mode 100644 index 1fbd9b9..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOBLoader.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the LWO importer class for the older LWOB - file formats, including materials */ - - -#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER - -// Internal headers -#include "LWOLoader.h" -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWOBFile() -{ - LE_NCONST uint8_t* const end = mFileBuffer + fileSize; - bool running = true; - while (running) - { - if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; - const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - { - throw DeadlyImportError("LWOB: Invalid chunk length"); - break; - } - uint8_t* const next = mFileBuffer+head.length; - switch (head.type) - { - // vertex list - case AI_LWO_PNTS: - { - if (!mCurLayer->mTempPoints.empty()) - ASSIMP_LOG_WARN("LWO: PNTS chunk encountered twice"); - else LoadLWOPoints(head.length); - break; - } - // face list - case AI_LWO_POLS: - { - - if (!mCurLayer->mFaces.empty()) - ASSIMP_LOG_WARN("LWO: POLS chunk encountered twice"); - else LoadLWOBPolygons(head.length); - break; - } - // list of tags - case AI_LWO_SRFS: - { - if (!mTags->empty()) - ASSIMP_LOG_WARN("LWO: SRFS chunk encountered twice"); - else LoadLWOTags(head.length); - break; - } - - // surface chunk - case AI_LWO_SURF: - { - LoadLWOBSurface(head.length); - break; - } - } - mFileBuffer = next; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWOBPolygons(unsigned int length) -{ - // first find out how many faces and vertices we'll finally need - LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length); - LE_NCONST uint16_t* cursor = (LE_NCONST uint16_t*)mFileBuffer; - - // perform endianness conversions -#ifndef AI_BUILD_BIG_ENDIAN - while (cursor < end)ByteSwap::Swap2(cursor++); - cursor = (LE_NCONST uint16_t*)mFileBuffer; -#endif - - unsigned int iNumFaces = 0,iNumVertices = 0; - CountVertsAndFacesLWOB(iNumVertices,iNumFaces,cursor,end); - - // allocate the output array and copy face indices - if (iNumFaces) - { - cursor = (LE_NCONST uint16_t*)mFileBuffer; - - mCurLayer->mFaces.resize(iNumFaces); - FaceList::iterator it = mCurLayer->mFaces.begin(); - CopyFaceIndicesLWOB(it,cursor,end); - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::CountVertsAndFacesLWOB(unsigned int& verts, unsigned int& faces, - LE_NCONST uint16_t*& cursor, const uint16_t* const end, unsigned int max) -{ - while (cursor < end && max--) - { - uint16_t numIndices; - // must have 2 shorts left for numIndices and surface - if (end - cursor < 2) { - throw DeadlyImportError("LWOB: Unexpected end of file"); - } - ::memcpy(&numIndices, cursor++, 2); - // must have enough left for indices and surface - if (end - cursor < (1 + numIndices)) { - throw DeadlyImportError("LWOB: Unexpected end of file"); - } - verts += numIndices; - faces++; - cursor += numIndices; - int16_t surface; - ::memcpy(&surface, cursor++, 2); - if (surface < 0) - { - // there are detail polygons - ::memcpy(&numIndices, cursor++, 2); - CountVertsAndFacesLWOB(verts,faces,cursor,end,numIndices); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::CopyFaceIndicesLWOB(FaceList::iterator& it, - LE_NCONST uint16_t*& cursor, - const uint16_t* const end, - unsigned int max) -{ - while (cursor < end && max--) - { - LWO::Face& face = *it;++it; - uint16_t numIndices; - ::memcpy(&numIndices, cursor++, 2); - face.mNumIndices = numIndices; - if(face.mNumIndices) - { - if (cursor + face.mNumIndices >= end) - { - break; - } - face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i) { - unsigned int & mi = face.mIndices[i]; - uint16_t index; - ::memcpy(&index, cursor++, 2); - mi = index; - if (mi > mCurLayer->mTempPoints.size()) - { - ASSIMP_LOG_WARN("LWOB: face index is out of range"); - mi = (unsigned int)mCurLayer->mTempPoints.size()-1; - } - } - } else { - ASSIMP_LOG_WARN("LWOB: Face has 0 indices"); - } - int16_t surface; - ::memcpy(&surface, cursor++, 2); - if (surface < 0) - { - surface = -surface; - - // there are detail polygons. - uint16_t numPolygons; - ::memcpy(&numPolygons, cursor++, 2); - if (cursor < end) - { - CopyFaceIndicesLWOB(it,cursor,end,numPolygons); - } - } - face.surfaceIndex = surface-1; - } -} - -// ------------------------------------------------------------------------------------------------ -LWO::Texture* LWOImporter::SetupNewTextureLWOB(LWO::TextureList& list,unsigned int size) -{ - list.push_back(LWO::Texture()); - LWO::Texture* tex = &list.back(); - - std::string type; - GetS0(type,size); - const char* s = type.c_str(); - - if(strstr(s, "Image Map")) - { - // Determine mapping type - if(strstr(s, "Planar")) - tex->mapMode = LWO::Texture::Planar; - else if(strstr(s, "Cylindrical")) - tex->mapMode = LWO::Texture::Cylindrical; - else if(strstr(s, "Spherical")) - tex->mapMode = LWO::Texture::Spherical; - else if(strstr(s, "Cubic")) - tex->mapMode = LWO::Texture::Cubic; - else if(strstr(s, "Front")) - tex->mapMode = LWO::Texture::FrontProjection; - } - else - { - // procedural or gradient, not supported - ASSIMP_LOG_ERROR("LWOB: Unsupported legacy texture: ", type); - } - - return tex; -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWOBSurface(unsigned int size) -{ - LE_NCONST uint8_t* const end = mFileBuffer + size; - - mSurfaces->push_back( LWO::Surface () ); - LWO::Surface& surf = mSurfaces->back(); - LWO::Texture *pTex = nullptr; - - GetS0(surf.mName,size); - bool running = true; - while (running) { - if (mFileBuffer + 6 >= end) - break; - - IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - /* A single test file (sonycam.lwo) seems to have invalid surface chunks. - * I'm assuming it's the fault of a single, unknown exporter so there are - * probably THOUSANDS of them. Here's a dirty workaround: - * - * We don't break if the chunk limit is exceeded. Instead, we're computing - * how much storage is actually left and work with this value from now on. - */ - if (mFileBuffer + head.length > end) { - ASSIMP_LOG_ERROR("LWOB: Invalid surface chunk length. Trying to continue."); - head.length = (uint16_t) (end - mFileBuffer); - } - - uint8_t* const next = mFileBuffer+head.length; - switch (head.type) - { - // diffuse color - case AI_LWO_COLR: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,COLR,3); - surf.mColor.r = GetU1() / 255.0f; - surf.mColor.g = GetU1() / 255.0f; - surf.mColor.b = GetU1() / 255.0f; - break; - } - // diffuse strength ... - case AI_LWO_DIFF: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,DIFF,2); - surf.mDiffuseValue = GetU2() / 255.0f; - break; - } - // specular strength ... - case AI_LWO_SPEC: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SPEC,2); - surf.mSpecularValue = GetU2() / 255.0f; - break; - } - // luminosity ... - case AI_LWO_LUMI: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,LUMI,2); - surf.mLuminosity = GetU2() / 255.0f; - break; - } - // transparency - case AI_LWO_TRAN: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TRAN,2); - surf.mTransparency = GetU2() / 255.0f; - break; - } - // surface flags - case AI_LWO_FLAG: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,FLAG,2); - uint16_t flag = GetU2(); - if (flag & 0x4 ) surf.mMaximumSmoothAngle = 1.56207f; - if (flag & 0x8 ) surf.mColorHighlights = 1.f; - if (flag & 0x100) surf.bDoubleSided = true; - break; - } - // maximum smoothing angle - case AI_LWO_SMAN: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,SMAN,4); - surf.mMaximumSmoothAngle = std::fabs( GetF4() ); - break; - } - // glossiness - case AI_LWO_GLOS: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,GLOS,2); - surf.mGlossiness = (float)GetU2(); - break; - } - // color texture - case AI_LWO_CTEX: - { - pTex = SetupNewTextureLWOB(surf.mColorTextures, - head.length); - break; - } - // diffuse texture - case AI_LWO_DTEX: - { - pTex = SetupNewTextureLWOB(surf.mDiffuseTextures, - head.length); - break; - } - // specular texture - case AI_LWO_STEX: - { - pTex = SetupNewTextureLWOB(surf.mSpecularTextures, - head.length); - break; - } - // bump texture - case AI_LWO_BTEX: - { - pTex = SetupNewTextureLWOB(surf.mBumpTextures, - head.length); - break; - } - // transparency texture - case AI_LWO_TTEX: - { - pTex = SetupNewTextureLWOB(surf.mOpacityTextures, - head.length); - break; - } - // texture path - case AI_LWO_TIMG: - { - if (pTex) { - GetS0(pTex->mFileName,head.length); - } else { - ASSIMP_LOG_WARN("LWOB: Unexpected TIMG chunk"); - } - break; - } - // texture strength - case AI_LWO_TVAL: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TVAL,1); - if (pTex) { - pTex->mStrength = (float)GetU1()/ 255.f; - } else { - ASSIMP_LOG_ERROR("LWOB: Unexpected TVAL chunk"); - } - break; - } - // texture flags - case AI_LWO_TFLG: - { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length,TFLG,2); - - if (nullptr != pTex) { - const uint16_t s = GetU2(); - if (s & 1) - pTex->majorAxis = LWO::Texture::AXIS_X; - else if (s & 2) - pTex->majorAxis = LWO::Texture::AXIS_Y; - else if (s & 4) - pTex->majorAxis = LWO::Texture::AXIS_Z; - - if (s & 16) { - ASSIMP_LOG_WARN("LWOB: Ignoring \'negate\' flag on texture"); - } - } - else { - ASSIMP_LOG_WARN("LWOB: Unexpected TFLG chunk"); - } - break; - } - } - mFileBuffer = next; - } -} - -#endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER diff --git a/libs/assimp/code/AssetLib/LWO/LWOFileData.h b/libs/assimp/code/AssetLib/LWO/LWOFileData.h deleted file mode 100644 index f477f58..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOFileData.h +++ /dev/null @@ -1,638 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file LWOFileData.h - * @brief Defines chunk constants used by the LWO file format - -The chunks are taken from the official LightWave SDK headers. - -*/ -#ifndef AI_LWO_FILEDATA_INCLUDED -#define AI_LWO_FILEDATA_INCLUDED - -// STL headers -#include -#include - -// public ASSIMP headers -#include - -// internal headers -#include "AssetLib/LWO/LWOAnimation.h" -#include "Common/IFF.h" - -namespace Assimp { -namespace LWO { - -#define AI_LWO_FOURCC_LWOB AI_IFF_FOURCC('L', 'W', 'O', 'B') -#define AI_LWO_FOURCC_LWO2 AI_IFF_FOURCC('L', 'W', 'O', '2') -#define AI_LWO_FOURCC_LXOB AI_IFF_FOURCC('L', 'X', 'O', 'B') - -// chunks specific to the LWOB format -#define AI_LWO_SRFS AI_IFF_FOURCC('S', 'R', 'F', 'S') -#define AI_LWO_FLAG AI_IFF_FOURCC('F', 'L', 'A', 'G') -#define AI_LWO_VLUM AI_IFF_FOURCC('V', 'L', 'U', 'M') -#define AI_LWO_VDIF AI_IFF_FOURCC('V', 'D', 'I', 'F') -#define AI_LWO_VSPC AI_IFF_FOURCC('V', 'S', 'P', 'C') -#define AI_LWO_RFLT AI_IFF_FOURCC('R', 'F', 'L', 'T') -#define AI_LWO_BTEX AI_IFF_FOURCC('B', 'T', 'E', 'X') -#define AI_LWO_CTEX AI_IFF_FOURCC('C', 'T', 'E', 'X') -#define AI_LWO_DTEX AI_IFF_FOURCC('D', 'T', 'E', 'X') -#define AI_LWO_LTEX AI_IFF_FOURCC('L', 'T', 'E', 'X') -#define AI_LWO_RTEX AI_IFF_FOURCC('R', 'T', 'E', 'X') -#define AI_LWO_STEX AI_IFF_FOURCC('S', 'T', 'E', 'X') -#define AI_LWO_TTEX AI_IFF_FOURCC('T', 'T', 'E', 'X') -#define AI_LWO_TFLG AI_IFF_FOURCC('T', 'F', 'L', 'G') -#define AI_LWO_TSIZ AI_IFF_FOURCC('T', 'S', 'I', 'Z') -#define AI_LWO_TCTR AI_IFF_FOURCC('T', 'C', 'T', 'R') -#define AI_LWO_TFAL AI_IFF_FOURCC('T', 'F', 'A', 'L') -#define AI_LWO_TVEL AI_IFF_FOURCC('T', 'V', 'E', 'L') -#define AI_LWO_TCLR AI_IFF_FOURCC('T', 'C', 'L', 'R') -#define AI_LWO_TVAL AI_IFF_FOURCC('T', 'V', 'A', 'L') -#define AI_LWO_TAMP AI_IFF_FOURCC('T', 'A', 'M', 'P') -#define AI_LWO_TIMG AI_IFF_FOURCC('T', 'I', 'M', 'G') -#define AI_LWO_TAAS AI_IFF_FOURCC('T', 'A', 'A', 'S') -#define AI_LWO_TREF AI_IFF_FOURCC('T', 'R', 'E', 'F') -#define AI_LWO_TOPC AI_IFF_FOURCC('T', 'O', 'P', 'C') -#define AI_LWO_SDAT AI_IFF_FOURCC('S', 'D', 'A', 'T') -#define AI_LWO_TFP0 AI_IFF_FOURCC('T', 'F', 'P', '0') -#define AI_LWO_TFP1 AI_IFF_FOURCC('T', 'F', 'P', '1') - -/* top-level chunks */ -#define AI_LWO_LAYR AI_IFF_FOURCC('L', 'A', 'Y', 'R') -#define AI_LWO_TAGS AI_IFF_FOURCC('T', 'A', 'G', 'S') -#define AI_LWO_PNTS AI_IFF_FOURCC('P', 'N', 'T', 'S') -#define AI_LWO_BBOX AI_IFF_FOURCC('B', 'B', 'O', 'X') -#define AI_LWO_VMAP AI_IFF_FOURCC('V', 'M', 'A', 'P') -#define AI_LWO_VMAD AI_IFF_FOURCC('V', 'M', 'A', 'D') -#define AI_LWO_POLS AI_IFF_FOURCC('P', 'O', 'L', 'S') -#define AI_LWO_PTAG AI_IFF_FOURCC('P', 'T', 'A', 'G') -#define AI_LWO_ENVL AI_IFF_FOURCC('E', 'N', 'V', 'L') -#define AI_LWO_CLIP AI_IFF_FOURCC('C', 'L', 'I', 'P') -#define AI_LWO_SURF AI_IFF_FOURCC('S', 'U', 'R', 'F') -#define AI_LWO_DESC AI_IFF_FOURCC('D', 'E', 'S', 'C') -#define AI_LWO_TEXT AI_IFF_FOURCC('T', 'E', 'X', 'T') -#define AI_LWO_ICON AI_IFF_FOURCC('I', 'C', 'O', 'N') - -/* polygon types */ -#define AI_LWO_FACE AI_IFF_FOURCC('F', 'A', 'C', 'E') -#define AI_LWO_CURV AI_IFF_FOURCC('C', 'U', 'R', 'V') -#define AI_LWO_PTCH AI_IFF_FOURCC('P', 'T', 'C', 'H') -#define AI_LWO_MBAL AI_IFF_FOURCC('M', 'B', 'A', 'L') -#define AI_LWO_BONE AI_IFF_FOURCC('B', 'O', 'N', 'E') -#define AI_LWO_SUBD AI_IFF_FOURCC('S', 'U', 'B', 'D') - -/* polygon tags */ -#define AI_LWO_SURF AI_IFF_FOURCC('S', 'U', 'R', 'F') -#define AI_LWO_PART AI_IFF_FOURCC('P', 'A', 'R', 'T') -#define AI_LWO_SMGP AI_IFF_FOURCC('S', 'M', 'G', 'P') - -/* envelopes */ -#define AI_LWO_PRE AI_IFF_FOURCC('P', 'R', 'E', ' ') -#define AI_LWO_POST AI_IFF_FOURCC('P', 'O', 'S', 'T') -#define AI_LWO_KEY AI_IFF_FOURCC('K', 'E', 'Y', ' ') -#define AI_LWO_SPAN AI_IFF_FOURCC('S', 'P', 'A', 'N') -#define AI_LWO_TCB AI_IFF_FOURCC('T', 'C', 'B', ' ') -#define AI_LWO_HERM AI_IFF_FOURCC('H', 'E', 'R', 'M') -#define AI_LWO_BEZI AI_IFF_FOURCC('B', 'E', 'Z', 'I') -#define AI_LWO_BEZ2 AI_IFF_FOURCC('B', 'E', 'Z', '2') -#define AI_LWO_LINE AI_IFF_FOURCC('L', 'I', 'N', 'E') -#define AI_LWO_STEP AI_IFF_FOURCC('S', 'T', 'E', 'P') - -/* clips */ -#define AI_LWO_STIL AI_IFF_FOURCC('S', 'T', 'I', 'L') -#define AI_LWO_ISEQ AI_IFF_FOURCC('I', 'S', 'E', 'Q') -#define AI_LWO_ANIM AI_IFF_FOURCC('A', 'N', 'I', 'M') -#define AI_LWO_XREF AI_IFF_FOURCC('X', 'R', 'E', 'F') -#define AI_LWO_STCC AI_IFF_FOURCC('S', 'T', 'C', 'C') -#define AI_LWO_TIME AI_IFF_FOURCC('T', 'I', 'M', 'E') -#define AI_LWO_CONT AI_IFF_FOURCC('C', 'O', 'N', 'T') -#define AI_LWO_BRIT AI_IFF_FOURCC('B', 'R', 'I', 'T') -#define AI_LWO_SATR AI_IFF_FOURCC('S', 'A', 'T', 'R') -#define AI_LWO_HUE AI_IFF_FOURCC('H', 'U', 'E', ' ') -#define AI_LWO_GAMM AI_IFF_FOURCC('G', 'A', 'M', 'M') -#define AI_LWO_NEGA AI_IFF_FOURCC('N', 'E', 'G', 'A') -#define AI_LWO_IFLT AI_IFF_FOURCC('I', 'F', 'L', 'T') -#define AI_LWO_PFLT AI_IFF_FOURCC('P', 'F', 'L', 'T') - -/* surfaces */ -#define AI_LWO_COLR AI_IFF_FOURCC('C', 'O', 'L', 'R') -#define AI_LWO_LUMI AI_IFF_FOURCC('L', 'U', 'M', 'I') -#define AI_LWO_DIFF AI_IFF_FOURCC('D', 'I', 'F', 'F') -#define AI_LWO_SPEC AI_IFF_FOURCC('S', 'P', 'E', 'C') -#define AI_LWO_GLOS AI_IFF_FOURCC('G', 'L', 'O', 'S') -#define AI_LWO_REFL AI_IFF_FOURCC('R', 'E', 'F', 'L') -#define AI_LWO_RFOP AI_IFF_FOURCC('R', 'F', 'O', 'P') -#define AI_LWO_RIMG AI_IFF_FOURCC('R', 'I', 'M', 'G') -#define AI_LWO_RSAN AI_IFF_FOURCC('R', 'S', 'A', 'N') -#define AI_LWO_TRAN AI_IFF_FOURCC('T', 'R', 'A', 'N') -#define AI_LWO_TROP AI_IFF_FOURCC('T', 'R', 'O', 'P') -#define AI_LWO_TIMG AI_IFF_FOURCC('T', 'I', 'M', 'G') -#define AI_LWO_RIND AI_IFF_FOURCC('R', 'I', 'N', 'D') -#define AI_LWO_TRNL AI_IFF_FOURCC('T', 'R', 'N', 'L') -#define AI_LWO_BUMP AI_IFF_FOURCC('B', 'U', 'M', 'P') -#define AI_LWO_SMAN AI_IFF_FOURCC('S', 'M', 'A', 'N') -#define AI_LWO_SIDE AI_IFF_FOURCC('S', 'I', 'D', 'E') -#define AI_LWO_CLRH AI_IFF_FOURCC('C', 'L', 'R', 'H') -#define AI_LWO_CLRF AI_IFF_FOURCC('C', 'L', 'R', 'F') -#define AI_LWO_ADTR AI_IFF_FOURCC('A', 'D', 'T', 'R') -#define AI_LWO_SHRP AI_IFF_FOURCC('S', 'H', 'R', 'P') -#define AI_LWO_LINE AI_IFF_FOURCC('L', 'I', 'N', 'E') -#define AI_LWO_LSIZ AI_IFF_FOURCC('L', 'S', 'I', 'Z') -#define AI_LWO_ALPH AI_IFF_FOURCC('A', 'L', 'P', 'H') -#define AI_LWO_AVAL AI_IFF_FOURCC('A', 'V', 'A', 'L') -#define AI_LWO_GVAL AI_IFF_FOURCC('G', 'V', 'A', 'L') -#define AI_LWO_BLOK AI_IFF_FOURCC('B', 'L', 'O', 'K') -#define AI_LWO_VCOL AI_IFF_FOURCC('V', 'C', 'O', 'L') - -/* texture layer */ -#define AI_LWO_TYPE AI_IFF_FOURCC('T', 'Y', 'P', 'E') -#define AI_LWO_CHAN AI_IFF_FOURCC('C', 'H', 'A', 'N') -#define AI_LWO_NAME AI_IFF_FOURCC('N', 'A', 'M', 'E') -#define AI_LWO_ENAB AI_IFF_FOURCC('E', 'N', 'A', 'B') -#define AI_LWO_OPAC AI_IFF_FOURCC('O', 'P', 'A', 'C') -#define AI_LWO_FLAG AI_IFF_FOURCC('F', 'L', 'A', 'G') -#define AI_LWO_PROJ AI_IFF_FOURCC('P', 'R', 'O', 'J') -#define AI_LWO_STCK AI_IFF_FOURCC('S', 'T', 'C', 'K') -#define AI_LWO_TAMP AI_IFF_FOURCC('T', 'A', 'M', 'P') - -/* texture coordinates */ -#define AI_LWO_TMAP AI_IFF_FOURCC('T', 'M', 'A', 'P') -#define AI_LWO_AXIS AI_IFF_FOURCC('A', 'X', 'I', 'S') -#define AI_LWO_CNTR AI_IFF_FOURCC('C', 'N', 'T', 'R') -#define AI_LWO_SIZE AI_IFF_FOURCC('S', 'I', 'Z', 'E') -#define AI_LWO_ROTA AI_IFF_FOURCC('R', 'O', 'T', 'A') -#define AI_LWO_OREF AI_IFF_FOURCC('O', 'R', 'E', 'F') -#define AI_LWO_FALL AI_IFF_FOURCC('F', 'A', 'L', 'L') -#define AI_LWO_CSYS AI_IFF_FOURCC('C', 'S', 'Y', 'S') - -/* image map */ -#define AI_LWO_IMAP AI_IFF_FOURCC('I', 'M', 'A', 'P') -#define AI_LWO_IMAG AI_IFF_FOURCC('I', 'M', 'A', 'G') -#define AI_LWO_WRAP AI_IFF_FOURCC('W', 'R', 'A', 'P') -#define AI_LWO_WRPW AI_IFF_FOURCC('W', 'R', 'P', 'W') -#define AI_LWO_WRPH AI_IFF_FOURCC('W', 'R', 'P', 'H') -#define AI_LWO_VMAP AI_IFF_FOURCC('V', 'M', 'A', 'P') -#define AI_LWO_AAST AI_IFF_FOURCC('A', 'A', 'S', 'T') -#define AI_LWO_PIXB AI_IFF_FOURCC('P', 'I', 'X', 'B') - -/* procedural */ -#define AI_LWO_PROC AI_IFF_FOURCC('P', 'R', 'O', 'C') -#define AI_LWO_COLR AI_IFF_FOURCC('C', 'O', 'L', 'R') -#define AI_LWO_VALU AI_IFF_FOURCC('V', 'A', 'L', 'U') -#define AI_LWO_FUNC AI_IFF_FOURCC('F', 'U', 'N', 'C') -#define AI_LWO_FTPS AI_IFF_FOURCC('F', 'T', 'P', 'S') -#define AI_LWO_ITPS AI_IFF_FOURCC('I', 'T', 'P', 'S') -#define AI_LWO_ETPS AI_IFF_FOURCC('E', 'T', 'P', 'S') - -/* gradient */ -#define AI_LWO_GRAD AI_IFF_FOURCC('G', 'R', 'A', 'D') -#define AI_LWO_GRST AI_IFF_FOURCC('G', 'R', 'S', 'T') -#define AI_LWO_GREN AI_IFF_FOURCC('G', 'R', 'E', 'N') -#define AI_LWO_PNAM AI_IFF_FOURCC('P', 'N', 'A', 'M') -#define AI_LWO_INAM AI_IFF_FOURCC('I', 'N', 'A', 'M') -#define AI_LWO_GRPT AI_IFF_FOURCC('G', 'R', 'P', 'T') -#define AI_LWO_FKEY AI_IFF_FOURCC('F', 'K', 'E', 'Y') -#define AI_LWO_IKEY AI_IFF_FOURCC('I', 'K', 'E', 'Y') - -/* shader */ -#define AI_LWO_SHDR AI_IFF_FOURCC('S', 'H', 'D', 'R') -#define AI_LWO_DATA AI_IFF_FOURCC('D', 'A', 'T', 'A') - -/* VMAP types */ -#define AI_LWO_TXUV AI_IFF_FOURCC('T', 'X', 'U', 'V') -#define AI_LWO_RGB AI_IFF_FOURCC('R', 'G', 'B', ' ') -#define AI_LWO_RGBA AI_IFF_FOURCC('R', 'G', 'B', 'A') -#define AI_LWO_WGHT AI_IFF_FOURCC('W', 'G', 'H', 'T') - -#define AI_LWO_MNVW AI_IFF_FOURCC('M', 'N', 'V', 'W') -#define AI_LWO_MORF AI_IFF_FOURCC('M', 'O', 'R', 'F') -#define AI_LWO_SPOT AI_IFF_FOURCC('S', 'P', 'O', 'T') -#define AI_LWO_PICK AI_IFF_FOURCC('P', 'I', 'C', 'K') - -// MODO extension - per-vertex normal vectors -#define AI_LWO_MODO_NORM AI_IFF_FOURCC('N', 'O', 'R', 'M') - -// --------------------------------------------------------------------------- -/** \brief Data structure for a face in a LWO file - * - * \note We can't use the code in SmoothingGroups.inl here - the mesh - * structures of 3DS/ASE and LWO are too different. - */ -struct Face : public aiFace { - //! Default construction - Face() AI_NO_EXCEPT - : surfaceIndex(0), - smoothGroup(0), - type(AI_LWO_FACE) { - // empty - } - - //! Construction from given type - explicit Face(uint32_t _type) : - surfaceIndex(0), smoothGroup(0), type(_type) {} - - //! Copy construction - Face(const Face &f) : - aiFace() { - *this = f; - } - - //! Zero-based index into tags chunk - unsigned int surfaceIndex; - - //! Smooth group this face is assigned to - unsigned int smoothGroup; - - //! Type of face - uint32_t type; - - //! Assignment operator - Face &operator=(const LWO::Face &f) { - aiFace::operator=(f); - surfaceIndex = f.surfaceIndex; - smoothGroup = f.smoothGroup; - type = f.type; - return *this; - } -}; - -// --------------------------------------------------------------------------- -/** \brief Base structure for all vertex map representations - */ -struct VMapEntry { - explicit VMapEntry(unsigned int _dims) : - dims(_dims) {} - - virtual ~VMapEntry() {} - - //! allocates memory for the vertex map - virtual void Allocate(unsigned int num) { - if (!rawData.empty()) - return; // return if already allocated - - const unsigned int m = num * dims; - rawData.reserve(m + (m >> 2u)); // 25% as extra storage for VMADs - rawData.resize(m, 0.f); - abAssigned.resize(num, false); - } - - std::string name; - unsigned int dims; - - std::vector rawData; - std::vector abAssigned; -}; - -// --------------------------------------------------------------------------- -/** \brief Represents an extra vertex color channel - */ -struct VColorChannel : public VMapEntry { - VColorChannel() : - VMapEntry(4) {} - - //! need to overwrite this function - the alpha channel must - //! be initialized to 1.0 by default - virtual void Allocate(unsigned int num) { - if (!rawData.empty()) - return; // return if already allocated - - unsigned int m = num * dims; - rawData.reserve(m + (m >> 2u)); // 25% as extra storage for VMADs - rawData.resize(m); - - for (aiColor4D *p = (aiColor4D *)&rawData[0]; p < (aiColor4D *)&rawData[m - 1]; ++p) - p->a = 1.f; - - abAssigned.resize(num, false); - } -}; - -// --------------------------------------------------------------------------- -/** \brief Represents an extra vertex UV channel - */ -struct UVChannel : public VMapEntry { - UVChannel() : - VMapEntry(2) {} -}; - -// --------------------------------------------------------------------------- -/** \brief Represents a weight map - */ -struct WeightChannel : public VMapEntry { - WeightChannel() : - VMapEntry(1) {} -}; - -// --------------------------------------------------------------------------- -/** \brief Represents a vertex-normals channel (MODO extension) - */ -struct NormalChannel : public VMapEntry { - NormalChannel() : - VMapEntry(3) {} -}; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO file texture - */ -struct Texture { - // we write the enum values out here to make debugging easier ... - enum BlendType { - Normal = 0, - Subtractive = 1, - Difference = 2, - Multiply = 3, - Divide = 4, - Alpha = 5, - TextureDispl = 6, - Additive = 7 - }; - - enum MappingMode { - Planar = 0, - Cylindrical = 1, - Spherical = 2, - Cubic = 3, - FrontProjection = 4, - UV = 5 - }; - - enum Axes { - AXIS_X = 0, - AXIS_Y = 1, - AXIS_Z = 2 - }; - - enum Wrap { - RESET = 0, - REPEAT = 1, - MIRROR = 2, - EDGE = 3 - }; - - Texture() : - mClipIdx(UINT_MAX), mStrength(1.0f), type(), mUVChannelIndex("unknown"), mRealUVIndex(UINT_MAX), enabled(true), blendType(Additive), bCanUse(true), mapMode(UV), majorAxis(AXIS_X), wrapAmountH(1.0f), wrapAmountW(1.0f), wrapModeWidth(REPEAT), wrapModeHeight(REPEAT), ordinal("\x00") {} - - //! File name of the texture - std::string mFileName; - - //! Clip index - unsigned int mClipIdx; - - //! Strength of the texture - blend factor - float mStrength; - - uint32_t type; // type of the texture - - //! Name of the corresponding UV channel - std::string mUVChannelIndex; - unsigned int mRealUVIndex; - - //! is the texture enabled? - bool enabled; - - //! blend type - BlendType blendType; - - //! are we able to use the texture? - bool bCanUse; - - //! mapping mode - MappingMode mapMode; - - //! major axis for planar, cylindrical, spherical projections - Axes majorAxis; - - //! wrap amount for cylindrical and spherical projections - float wrapAmountH, wrapAmountW; - - //! wrapping mode for the texture - Wrap wrapModeWidth, wrapModeHeight; - - //! ordinal string of the texture - std::string ordinal; -}; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO file clip - */ -struct Clip { - enum Type { - STILL, - SEQ, - REF, - UNSUPPORTED - } type; - - Clip() : - type(UNSUPPORTED), clipRef(), idx(0), negate(false) {} - - //! path to the base texture - - std::string path; - - //! reference to another CLIP - unsigned int clipRef; - - //! index of the clip - unsigned int idx; - - //! Negate the clip? - bool negate; -}; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO file shader - * - * Later - */ -struct Shader { - Shader() : - ordinal("\x00"), functionName("unknown"), enabled(true) {} - - std::string ordinal; - std::string functionName; - bool enabled; -}; - -typedef std::list TextureList; -typedef std::list ShaderList; - -// --------------------------------------------------------------------------- -/** \brief Data structure for a LWO file surface (= material) - */ -struct Surface { - Surface() : - mColor(0.78431f, 0.78431f, 0.78431f), bDoubleSided(false), mDiffuseValue(1.f), mSpecularValue(0.f), mTransparency(0.f), mGlossiness(0.4f), mLuminosity(0.f), mColorHighlights(0.f), mMaximumSmoothAngle(0.f) // 0 == not specified, no smoothing - , - mVCMap(), - mVCMapType(AI_LWO_RGBA), - mIOR(1.f) // vakuum - , - mBumpIntensity(1.f), - mWireframe(false), - mAdditiveTransparency(0.f) {} - - //! Name of the surface - std::string mName; - - //! Color of the surface - aiColor3D mColor; - - //! true for two-sided materials - bool bDoubleSided; - - //! Various material parameters - float mDiffuseValue, mSpecularValue, mTransparency, mGlossiness, mLuminosity, mColorHighlights; - - //! Maximum angle between two adjacent triangles - //! that they can be smoothed - in degrees - float mMaximumSmoothAngle; - - //! Vertex color map to be used to color the surface - std::string mVCMap; - uint32_t mVCMapType; - - //! Names of the special shaders to be applied to the surface - ShaderList mShaders; - - //! Textures - the first entry in the list is evaluated first - TextureList mColorTextures, // color textures are added to both diffuse and specular texture stacks - mDiffuseTextures, - mSpecularTextures, - mOpacityTextures, - mBumpTextures, - mGlossinessTextures, - mReflectionTextures; - - //! Index of refraction - float mIOR; - - //! Bump intensity scaling - float mBumpIntensity; - - //! Wireframe flag - bool mWireframe; - - //! Intensity of additive blending - float mAdditiveTransparency; -}; - -// --------------------------------------------------------------------------- -#define AI_LWO_VALIDATE_CHUNK_LENGTH(length, name, size) \ - if (length < size) { \ - throw DeadlyImportError("LWO: " #name " chunk is too small"); \ - } - -// some typedefs ... to make life with loader monsters like this easier -typedef std::vector PointList; -typedef std::vector FaceList; -typedef std::vector SurfaceList; -typedef std::vector TagList; -typedef std::vector TagMappingTable; -typedef std::vector ReferrerList; -typedef std::vector WeightChannelList; -typedef std::vector VColorChannelList; -typedef std::vector UVChannelList; -typedef std::vector ClipList; -typedef std::vector EnvelopeList; -typedef std::vector SortedRep; - -// --------------------------------------------------------------------------- -/** \brief Represents a layer in the file - */ -struct Layer { - Layer() : - mFaceIDXOfs(0), mPointIDXOfs(0), mParent(0x0), mIndex(0xffff), skip(false) {} - - /** Temporary point list from the file */ - PointList mTempPoints; - - /** Lists for every point the index of another point - that has been copied from *this* point or UINT_MAX if - no copy of the point has been made */ - ReferrerList mPointReferrers; - - /** Weight channel list from the file */ - WeightChannelList mWeightChannels; - - /** Subdivision weight channel list from the file */ - WeightChannelList mSWeightChannels; - - /** Vertex color list from the file */ - VColorChannelList mVColorChannels; - - /** UV channel list from the file */ - UVChannelList mUVChannels; - - /** Normal vector channel from the file */ - NormalChannel mNormals; - - /** Temporary face list from the file*/ - FaceList mFaces; - - /** Current face indexing offset from the beginning of the buffers*/ - unsigned int mFaceIDXOfs; - - /** Current point indexing offset from the beginning of the buffers*/ - unsigned int mPointIDXOfs; - - /** Parent index */ - uint16_t mParent; - - /** Index of the layer */ - uint16_t mIndex; - - /** Name of the layer */ - std::string mName; - - /** Pivot point of the layer */ - aiVector3D mPivot; - - /** Skip this layer? */ - bool skip; -}; - -typedef std::list LayerList; - -} // namespace LWO -} // namespace Assimp - -#endif // !! AI_LWO_FILEDATA_INCLUDED diff --git a/libs/assimp/code/AssetLib/LWO/LWOLoader.cpp b/libs/assimp/code/AssetLib/LWO/LWOLoader.cpp deleted file mode 100644 index 7410fb6..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOLoader.cpp +++ /dev/null @@ -1,1422 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file LWOLoader.cpp - * @brief Implementation of the LWO importer class - */ - -#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER - -// internal headers -#include "AssetLib/LWO/LWOLoader.h" -#include "PostProcessing/ConvertToLHProcess.h" -#include "PostProcessing/ProcessHelper.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Assimp; - -static const aiImporterDesc desc = { - "LightWave/Modo Object Importer", - "", - "", - "https://www.lightwave3d.com/lightwave_sdk/", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "lwo lxo" -}; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -LWOImporter::LWOImporter() : - mIsLWO2(), - mIsLXOB(), - mLayers(), - mCurLayer(), - mTags(), - mMapping(), - mSurfaces(), - mFileBuffer(), - fileSize(), - mScene(nullptr), - configSpeedFlag(), - configLayerIndex(), - hasNamedLayer() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -LWOImporter::~LWOImporter() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. -bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const { - static const uint32_t tokens[] = { - AI_LWO_FOURCC_LWOB, - AI_LWO_FOURCC_LWO2, - AI_LWO_FOURCC_LXOB - }; - return CheckMagicToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens), 8); -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties -void LWOImporter::SetupProperties(const Importer *pImp) { - configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0) ? true : false); - configLayerIndex = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, UINT_MAX); - configLayerName = pImp->GetPropertyString(AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY, ""); -} - -// ------------------------------------------------------------------------------------------------ -// Get list of file extensions -const aiImporterDesc *LWOImporter::GetInfo() const { - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void LWOImporter::InternReadFile(const std::string &pFile, - aiScene *pScene, - IOSystem *pIOHandler) { - std::unique_ptr file(pIOHandler->Open(pFile, "rb")); - - // Check whether we can read from the file - if (file.get() == nullptr) { - throw DeadlyImportError("Failed to open LWO file ", pFile, "."); - } - - if ((this->fileSize = (unsigned int)file->FileSize()) < 12) { - throw DeadlyImportError("LWO: The file is too small to contain the IFF header"); - } - - // Allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer(fileSize); - file->Read(&mBuffer[0], 1, fileSize); - mScene = pScene; - - // Determine the type of the file - uint32_t fileType; - const char *sz = IFF::ReadHeader(&mBuffer[0], fileType); - if (sz) { - throw DeadlyImportError(sz); - } - - mFileBuffer = &mBuffer[0] + 12; - fileSize -= 12; - - // Initialize some members with their default values - hasNamedLayer = false; - - // Create temporary storage on the stack but store pointers to it in the class - // instance. Therefore everything will be destructed properly if an exception - // is thrown and we needn't take care of that. - LayerList _mLayers; - SurfaceList _mSurfaces; - TagList _mTags; - TagMappingTable _mMapping; - - mLayers = &_mLayers; - mTags = &_mTags; - mMapping = &_mMapping; - mSurfaces = &_mSurfaces; - - // Allocate a default layer (layer indices are 1-based from now) - mLayers->push_back(Layer()); - mCurLayer = &mLayers->back(); - mCurLayer->mName = ""; - mCurLayer->mIndex = (uint16_t) -1; - - // old lightwave file format (prior to v6) - if (AI_LWO_FOURCC_LWOB == fileType) { - ASSIMP_LOG_INFO("LWO file format: LWOB (<= LightWave 5.5)"); - - mIsLWO2 = false; - mIsLXOB = false; - LoadLWOBFile(); - } else if (AI_LWO_FOURCC_LWO2 == fileType) { - // New lightwave format - mIsLXOB = false; - ASSIMP_LOG_INFO("LWO file format: LWO2 (>= LightWave 6)"); - } else if (AI_LWO_FOURCC_LXOB == fileType) { - // MODO file format - mIsLXOB = true; - ASSIMP_LOG_INFO("LWO file format: LXOB (Modo)"); - } - else { - char szBuff[5]; - szBuff[0] = (char)(fileType >> 24u); - szBuff[1] = (char)(fileType >> 16u); - szBuff[2] = (char)(fileType >> 8u); - szBuff[3] = (char)(fileType); - szBuff[4] = '\0'; - throw DeadlyImportError("Unknown LWO sub format: ", szBuff); - } - - if (AI_LWO_FOURCC_LWOB != fileType) { - mIsLWO2 = true; - LoadLWO2File(); - - // The newer lightwave format allows the user to configure the - // loader that just one layer is used. If this is the case - // we need to check now whether the requested layer has been found. - if (UINT_MAX != configLayerIndex) { - unsigned int layerCount = 0; - for (std::list::iterator itLayers = mLayers->begin(); itLayers != mLayers->end(); ++itLayers) - if (!itLayers->skip) - layerCount++; - if (layerCount != 2) - throw DeadlyImportError("LWO2: The requested layer was not found"); - } - - if (configLayerName.length() && !hasNamedLayer) { - throw DeadlyImportError("LWO2: Unable to find the requested layer: ", configLayerName); - } - } - - // now, as we have loaded all data, we can resolve cross-referenced tags and clips - ResolveTags(); - ResolveClips(); - - // now process all layers and build meshes and nodes - std::vector apcMeshes; - std::map apcNodes; - - apcMeshes.reserve(mLayers->size() * std::min(((unsigned int)mSurfaces->size() / 2u), 1u)); - - unsigned int iDefaultSurface = UINT_MAX; // index of the default surface - for (LWO::Layer &layer : *mLayers) { - if (layer.skip) - continue; - - // I don't know whether there could be dummy layers, but it would be possible - const unsigned int meshStart = (unsigned int)apcMeshes.size(); - if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) { - - // now sort all faces by the surfaces assigned to them - std::vector pSorted(mSurfaces->size() + 1); - - unsigned int i = 0; - for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end(); it != end; ++it, ++i) { - // Check whether we support this face's type - if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH && - (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) { - continue; - } - - unsigned int idx = (*it).surfaceIndex; - if (idx >= mTags->size()) { - ASSIMP_LOG_WARN("LWO: Invalid face surface index"); - idx = UINT_MAX; - } - if (UINT_MAX == idx || UINT_MAX == (idx = _mMapping[idx])) { - if (UINT_MAX == iDefaultSurface) { - iDefaultSurface = (unsigned int)mSurfaces->size(); - mSurfaces->push_back(LWO::Surface()); - LWO::Surface &surf = mSurfaces->back(); - surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f; - surf.mName = "LWODefaultSurface"; - } - idx = iDefaultSurface; - } - pSorted[idx].push_back(i); - } - if (UINT_MAX == iDefaultSurface) { - pSorted.erase(pSorted.end() - 1); - } - for (unsigned int p = 0, j = 0; j < mSurfaces->size(); ++j) { - SortedRep &sorted = pSorted[j]; - if (sorted.empty()) - continue; - - // generate the mesh - aiMesh *mesh = new aiMesh(); - apcMeshes.push_back(mesh); - mesh->mNumFaces = (unsigned int)sorted.size(); - - // count the number of vertices - SortedRep::const_iterator it = sorted.begin(), end = sorted.end(); - for (; it != end; ++it) { - mesh->mNumVertices += layer.mFaces[*it].mNumIndices; - } - - aiVector3D *nrm = nullptr, *pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - aiFace *pf = mesh->mFaces = new aiFace[mesh->mNumFaces]; - mesh->mMaterialIndex = j; - - // find out which vertex color channels and which texture coordinate - // channels are really required by the material attached to this mesh - unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS]; - -#ifdef ASSIMP_BUILD_DEBUG - for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++mui) { - vUVChannelIndices[mui] = UINT_MAX; - } - for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS; ++mui) { - vVColorIndices[mui] = UINT_MAX; - } -#endif - - FindUVChannels(_mSurfaces[j], sorted, layer, vUVChannelIndices); - FindVCChannels(_mSurfaces[j], sorted, layer, vVColorIndices); - - // allocate storage for UV and CV channels - aiVector3D *pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++mui) { - if (UINT_MAX == vUVChannelIndices[mui]) { - break; - } - - pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices]; - - // LightWave doesn't support more than 2 UV components (?) - mesh->mNumUVComponents[0] = 2; - } - - if (layer.mNormals.name.length()) { - nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - } - - aiColor4D *pvVC[AI_MAX_NUMBER_OF_COLOR_SETS]; - for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS; ++mui) { - if (UINT_MAX == vVColorIndices[mui]) { - break; - } - pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices]; - } - - // we would not need this extra array, but the code is much cleaner if we use it - std::vector &smoothingGroups = layer.mPointReferrers; - smoothingGroups.erase(smoothingGroups.begin(), smoothingGroups.end()); - smoothingGroups.resize(mesh->mNumFaces, 0); - - // now convert all faces - unsigned int vert = 0; - std::vector::iterator outIt = smoothingGroups.begin(); - for (it = sorted.begin(); it != end; ++it, ++outIt) { - const LWO::Face &face = layer.mFaces[*it]; - *outIt = face.smoothGroup; - - // copy all vertices - for (unsigned int q = 0; q < face.mNumIndices; ++q, ++vert) { - unsigned int idx = face.mIndices[q]; - *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/; - - // process UV coordinates - for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++w) { - if (UINT_MAX == vUVChannelIndices[w]) { - break; - } - aiVector3D *&pp = pvUV[w]; - const aiVector2D &src = ((aiVector2D *)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx]; - pp->x = src.x; - pp->y = src.y; - pp++; - } - - // process normals (MODO extension) - if (nrm) { - *nrm = ((aiVector3D *)&layer.mNormals.rawData[0])[idx]; - nrm->z *= -1.f; - ++nrm; - } - - // process vertex colors - for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS; ++w) { - if (UINT_MAX == vVColorIndices[w]) { - break; - } - *pvVC[w] = ((aiColor4D *)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx]; - - // If a RGB color map is explicitly requested delete the - // alpha channel - it could theoretically be != 1. - if (_mSurfaces[j].mVCMapType == AI_LWO_RGB) - pvVC[w]->a = 1.f; - - pvVC[w]++; - } - -#if 0 - // process vertex weights. We can't properly reconstruct the whole skeleton for now, - // but we can create dummy bones for all weight channels which we have. - for (unsigned int w = 0; w < layer.mWeightChannels.size();++w) - { - } -#endif - - face.mIndices[q] = vert; - } - pf->mIndices = face.mIndices; - pf->mNumIndices = face.mNumIndices; - unsigned int **facePtr = (unsigned int **)&face.mIndices; - *facePtr = nullptr; // HACK: make sure it won't be deleted - pf++; - } - - if (!mesh->mNormals) { - // Compute normal vectors for the mesh - we can't use our GenSmoothNormal- - // Step here since it wouldn't handle smoothing groups correctly for LWO. - // So we use a separate implementation. - ComputeNormals(mesh, smoothingGroups, _mSurfaces[j]); - } else { - ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there"); - } - ++p; - } - } - - // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes - unsigned int num = static_cast(apcMeshes.size() - meshStart); - if (layer.mName != "" || num > 0) { - aiNode *pcNode = new aiNode(); - pcNode->mName.Set(layer.mName); - pcNode->mParent = (aiNode *)&layer; - pcNode->mNumMeshes = num; - - if (pcNode->mNumMeshes) { - pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; - for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p) - pcNode->mMeshes[p] = p + meshStart; - } - apcNodes[layer.mIndex] = pcNode; - } - } - - if (apcNodes.empty() || apcMeshes.empty()) - throw DeadlyImportError("LWO: No meshes loaded"); - - // The RemoveRedundantMaterials step will clean this up later - pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials = (unsigned int)mSurfaces->size()]; - for (unsigned int mat = 0; mat < pScene->mNumMaterials; ++mat) { - aiMaterial *pcMat = new aiMaterial(); - pScene->mMaterials[mat] = pcMat; - ConvertMaterial((*mSurfaces)[mat], pcMat); - } - - // copy the meshes to the output structure - pScene->mMeshes = new aiMesh *[pScene->mNumMeshes = (unsigned int)apcMeshes.size()]; - ::memcpy(pScene->mMeshes, &apcMeshes[0], pScene->mNumMeshes * sizeof(void *)); - - // generate the final node graph - GenerateNodeGraph(apcNodes); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::ComputeNormals(aiMesh *mesh, const std::vector &smoothingGroups, - const LWO::Surface &surface) { - // Allocate output storage - mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - - // First generate per-face normals - aiVector3D *out; - std::vector faceNormals; - - // ... in some cases that's already enough - if (!surface.mMaximumSmoothAngle) - out = mesh->mNormals; - else { - faceNormals.resize(mesh->mNumVertices); - out = &faceNormals[0]; - } - - aiFace *begin = mesh->mFaces, *const end = mesh->mFaces + mesh->mNumFaces; - for (; begin != end; ++begin) { - aiFace &face = *begin; - - if (face.mNumIndices < 3) { - continue; - } - - // LWO doc: "the normal is defined as the cross product of the first and last edges" - aiVector3D *pV1 = mesh->mVertices + face.mIndices[0]; - aiVector3D *pV2 = mesh->mVertices + face.mIndices[1]; - aiVector3D *pV3 = mesh->mVertices + face.mIndices[face.mNumIndices - 1]; - - aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize(); - for (unsigned int i = 0; i < face.mNumIndices; ++i) - out[face.mIndices[i]] = vNor; - } - if (!surface.mMaximumSmoothAngle) return; - const float posEpsilon = ComputePositionEpsilon(mesh); - - // Now generate the spatial sort tree - SGSpatialSort sSort; - std::vector::const_iterator it = smoothingGroups.begin(); - for (begin = mesh->mFaces; begin != end; ++begin, ++it) { - aiFace &face = *begin; - for (unsigned int i = 0; i < face.mNumIndices; ++i) { - unsigned int tt = face.mIndices[i]; - sSort.Add(mesh->mVertices[tt], tt, *it); - } - } - // Sort everything - this takes O(nlogn) time - sSort.Prepare(); - std::vector poResult; - poResult.reserve(20); - - // Generate vertex normals. We have O(logn) for the binary lookup, which we need - // for n elements, thus the EXPECTED complexity is O(nlogn) - if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag) { - const float fLimit = std::cos(surface.mMaximumSmoothAngle); - - for (begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) { - const aiFace &face = *begin; - unsigned int *beginIdx = face.mIndices, *const endIdx = face.mIndices + face.mNumIndices; - for (; beginIdx != endIdx; ++beginIdx) { - unsigned int idx = *beginIdx; - sSort.FindPositions(mesh->mVertices[idx], *it, posEpsilon, poResult, true); - - aiVector3D vNormals; - for (std::vector::const_iterator a = poResult.begin(); a != poResult.end(); ++a) { - const aiVector3D &v = faceNormals[*a]; - if (v * faceNormals[idx] < fLimit) - continue; - vNormals += v; - } - mesh->mNormals[idx] = vNormals.Normalize(); - } - } - } - // faster code path in case there is no smooth angle - else { - std::vector vertexDone(mesh->mNumVertices, false); - for (begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) { - const aiFace &face = *begin; - unsigned int *beginIdx = face.mIndices, *const endIdx = face.mIndices + face.mNumIndices; - for (; beginIdx != endIdx; ++beginIdx) { - unsigned int idx = *beginIdx; - if (vertexDone[idx]) - continue; - sSort.FindPositions(mesh->mVertices[idx], *it, posEpsilon, poResult, true); - - aiVector3D vNormals; - for (std::vector::const_iterator a = poResult.begin(); a != poResult.end(); ++a) { - const aiVector3D &v = faceNormals[*a]; - vNormals += v; - } - vNormals.Normalize(); - for (std::vector::const_iterator a = poResult.begin(); a != poResult.end(); ++a) { - mesh->mNormals[*a] = vNormals; - vertexDone[*a] = true; - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::GenerateNodeGraph(std::map &apcNodes) { - // now generate the final nodegraph - generate a root node and attach children - aiNode *root = mScene->mRootNode = new aiNode(); - root->mName.Set(""); - - //Set parent of all children, inserting pivots - std::map mapPivot; - for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { - - //Get the parent index - LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent); - uint16_t parentIndex = nodeLayer->mParent; - - //Create pivot node, store it into the pivot map, and set the parent as the pivot - aiNode *pivotNode = new aiNode(); - pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data)); - itapcNodes->second->mParent = pivotNode; - - //Look for the parent node to attach the pivot to - if (apcNodes.find(parentIndex) != apcNodes.end()) { - pivotNode->mParent = apcNodes[parentIndex]; - } else { - //If not, attach to the root node - pivotNode->mParent = root; - } - - //Set the node and the pivot node transformation - itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x; - itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y; - itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z; - pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; - pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; - pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; - mapPivot[-(itapcNodes->first + 2)] = pivotNode; - } - - //Merge pivot map into node map - for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { - apcNodes[itMapPivot->first] = itMapPivot->second; - } - - //Set children of all parents - apcNodes[(uint16_t)-1] = root; - for (auto itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) { - for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { - if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { - ++(itMapParentNodes->second->mNumChildren); - } - } - if (itMapParentNodes->second->mNumChildren) { - itMapParentNodes->second->mChildren = new aiNode *[itMapParentNodes->second->mNumChildren]; - uint16_t p = 0; - for (auto itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) { - if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) { - itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second; - } - } - } - } - - if (!mScene->mRootNode->mNumChildren) - throw DeadlyImportError("LWO: Unable to build a valid node graph"); - - // Remove a single root node with no meshes assigned to it ... - if (1 == mScene->mRootNode->mNumChildren) { - aiNode *pc = mScene->mRootNode->mChildren[0]; - pc->mParent = mScene->mRootNode->mChildren[0] = nullptr; - delete mScene->mRootNode; - mScene->mRootNode = pc; - } - - // convert the whole stuff to RH with CCW winding - MakeLeftHandedProcess maker; - maker.Execute(mScene); - - FlipWindingOrderProcess flipper; - flipper.Execute(mScene); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::ResolveTags() { - // --- this function is used for both LWO2 and LWOB - mMapping->resize(mTags->size(), UINT_MAX); - for (unsigned int a = 0; a < mTags->size(); ++a) { - - const std::string &c = (*mTags)[a]; - for (unsigned int i = 0; i < mSurfaces->size(); ++i) { - - const std::string &d = (*mSurfaces)[i].mName; - if (!ASSIMP_stricmp(c, d)) { - - (*mMapping)[a] = i; - break; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::ResolveClips() { - for (unsigned int i = 0; i < mClips.size(); ++i) { - - Clip &clip = mClips[i]; - if (Clip::REF == clip.type) { - - if (clip.clipRef >= mClips.size()) { - ASSIMP_LOG_ERROR("LWO2: Clip referrer index is out of range"); - clip.clipRef = 0; - } - - Clip &dest = mClips[clip.clipRef]; - if (Clip::REF == dest.type) { - ASSIMP_LOG_ERROR("LWO2: Clip references another clip reference"); - clip.type = Clip::UNSUPPORTED; - } - - else { - clip.path = dest.path; - clip.type = dest.type; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::AdjustTexturePath(std::string &out) { - // --- this function is used for both LWO2 and LWOB - if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) { - - // remove the (sequence) and append 000 - ASSIMP_LOG_INFO("LWOB: Sequence of animated texture found. It will be ignored"); - out = out.substr(0, out.length() - 10) + "000"; - } - - // format: drive:path/file - we just need to insert a slash after the drive - std::string::size_type n = out.find_first_of(':'); - if (std::string::npos != n) { - out.insert(n + 1, "/"); - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWOTags(unsigned int size) { - // --- this function is used for both LWO2 and LWOB - - const char *szCur = (const char *)mFileBuffer, *szLast = szCur; - const char *const szEnd = szLast + size; - while (szCur < szEnd) { - if (!(*szCur)) { - const size_t len = (size_t)(szCur - szLast); - // FIX: skip empty-sized tags - if (len) - mTags->push_back(std::string(szLast, len)); - szCur += (len & 0x1 ? 1 : 2); - szLast = szCur; - } - szCur++; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWOPoints(unsigned int length) { - // --- this function is used for both LWO2 and LWOB but for - // LWO2 we need to allocate 25% more storage - it could be we'll - // need to duplicate some points later. - const size_t vertexLen = 12; - if ((length % vertexLen) != 0) { - throw DeadlyImportError("LWO2: Points chunk length is not multiple of vertexLen (12)"); - } - unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12; - if (mIsLWO2) { - mCurLayer->mTempPoints.reserve(regularSize + (regularSize >> 2u)); - mCurLayer->mTempPoints.resize(regularSize); - - // initialize all point referrers with the default values - mCurLayer->mPointReferrers.reserve(regularSize + (regularSize >> 2u)); - mCurLayer->mPointReferrers.resize(regularSize, UINT_MAX); - } else - mCurLayer->mTempPoints.resize(regularSize); - - // perform endianness conversions -#ifndef AI_BUILD_BIG_ENDIAN - for (unsigned int i = 0; i> 2; ++i) - ByteSwap::Swap4(mFileBuffer + (i << 2)); -#endif - ::memcpy(&mCurLayer->mTempPoints[0], mFileBuffer, length); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2Polygons(unsigned int length) { - LE_NCONST uint16_t *const end = (LE_NCONST uint16_t *)(mFileBuffer + length); - const uint32_t type = GetU4(); - - // Determine the type of the polygons - switch (type) { - // read unsupported stuff too (although we won't process it) - case AI_LWO_MBAL: - ASSIMP_LOG_WARN("LWO2: Encountered unsupported primitive chunk (METABALL)"); - break; - case AI_LWO_CURV: - ASSIMP_LOG_WARN("LWO2: Encountered unsupported primitive chunk (SPLINE)"); - ; - break; - - // These are ok with no restrictions - case AI_LWO_PTCH: - case AI_LWO_FACE: - case AI_LWO_BONE: - case AI_LWO_SUBD: - break; - default: - - // hm!? wtf is this? ok ... - ASSIMP_LOG_ERROR("LWO2: Ignoring unknown polygon type."); - break; - } - - // first find out how many faces and vertices we'll finally need - uint16_t *cursor = (uint16_t *)mFileBuffer; - - unsigned int iNumFaces = 0, iNumVertices = 0; - CountVertsAndFacesLWO2(iNumVertices, iNumFaces, cursor, end); - - // allocate the output array and copy face indices - if (iNumFaces) { - cursor = (uint16_t *)mFileBuffer; - - mCurLayer->mFaces.resize(iNumFaces, LWO::Face(type)); - FaceList::iterator it = mCurLayer->mFaces.begin(); - CopyFaceIndicesLWO2(it, cursor, end); - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::CountVertsAndFacesLWO2(unsigned int &verts, unsigned int &faces, - uint16_t *&cursor, const uint16_t *const end, unsigned int max) { - while (cursor < end && max--) { - uint16_t numIndices; - ::memcpy(&numIndices, cursor++, 2); - AI_LSWAP2(numIndices); - numIndices &= 0x03FF; - - verts += numIndices; - ++faces; - - for (uint16_t i = 0; i < numIndices; i++) { - ReadVSizedIntLWO2((uint8_t *&)cursor); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator &it, - uint16_t *&cursor, - const uint16_t *const end) { - while (cursor < end) { - LWO::Face &face = *it++; - uint16_t numIndices; - ::memcpy(&numIndices, cursor++, 2); - AI_LSWAP2(numIndices); - face.mNumIndices = numIndices & 0x03FF; - - if (face.mNumIndices) /* byte swapping has already been done */ - { - face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices; i++) { - face.mIndices[i] = ReadVSizedIntLWO2((uint8_t *&)cursor) + mCurLayer->mPointIDXOfs; - if (face.mIndices[i] > mCurLayer->mTempPoints.size()) { - ASSIMP_LOG_WARN("LWO2: Failure evaluating face record, index is out of range"); - face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size() - 1; - } - } - } else - throw DeadlyImportError("LWO2: Encountered invalid face record with zero indices"); - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2PolygonTags(unsigned int length) { - LE_NCONST uint8_t *const end = mFileBuffer + length; - - AI_LWO_VALIDATE_CHUNK_LENGTH(length, PTAG, 4); - uint32_t type = GetU4(); - - if (type != AI_LWO_SURF && type != AI_LWO_SMGP) - return; - - while (mFileBuffer < end) { - unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs; - unsigned int j = GetU2(); - - if (i >= mCurLayer->mFaces.size()) { - ASSIMP_LOG_WARN("LWO2: face index in PTAG is out of range"); - continue; - } - - switch (type) { - - case AI_LWO_SURF: - mCurLayer->mFaces[i].surfaceIndex = j; - break; - case AI_LWO_SMGP: /* is that really used? */ - mCurLayer->mFaces[i].smoothGroup = j; - break; - }; - } -} - -// ------------------------------------------------------------------------------------------------ -template -VMapEntry *FindEntry(std::vector &list, const std::string &name, bool perPoly) { - for (auto &elem : list) { - if (elem.name == name) { - if (!perPoly) { - ASSIMP_LOG_WARN("LWO2: Found two VMAP sections with equal names"); - } - return &elem; - } - } - list.push_back(T()); - VMapEntry *p = &list.back(); - p->name = name; - return p; -} - -// ------------------------------------------------------------------------------------------------ -template -inline void CreateNewEntry(T &chan, unsigned int srcIdx) { - if (!chan.name.length()) - return; - - chan.abAssigned[srcIdx] = true; - chan.abAssigned.resize(chan.abAssigned.size() + 1, false); - - for (unsigned int a = 0; a < chan.dims; ++a) - chan.rawData.push_back(chan.rawData[srcIdx * chan.dims + a]); -} - -// ------------------------------------------------------------------------------------------------ -template -inline void CreateNewEntry(std::vector &list, unsigned int srcIdx) { - for (auto &elem : list) { - CreateNewEntry(elem, srcIdx); - } -} - -// ------------------------------------------------------------------------------------------------ -inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry *base, unsigned int numRead, - unsigned int idx, float *data) { - ai_assert(nullptr != data); - LWO::ReferrerList &refList = mCurLayer->mPointReferrers; - unsigned int i; - - if (idx >= base->abAssigned.size()) { - throw DeadlyImportError("Bad index"); - } - base->abAssigned[idx] = true; - for (i = 0; i < numRead; ++i) { - base->rawData[idx * base->dims + i] = data[i]; - } - - if (UINT_MAX != (i = refList[idx])) { - DoRecursiveVMAPAssignment(base, numRead, i, data); - } -} - -// ------------------------------------------------------------------------------------------------ -inline void AddToSingleLinkedList(ReferrerList &refList, unsigned int srcIdx, unsigned int destIdx) { - if (UINT_MAX == refList[srcIdx]) { - refList[srcIdx] = destIdx; - return; - } - AddToSingleLinkedList(refList, refList[srcIdx], destIdx); -} - -// ------------------------------------------------------------------------------------------------ -// Load LWO2 vertex map -void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly) { - LE_NCONST uint8_t *const end = mFileBuffer + length; - - AI_LWO_VALIDATE_CHUNK_LENGTH(length, VMAP, 6); - unsigned int type = GetU4(); - unsigned int dims = GetU2(); - - VMapEntry *base; - - // read the name of the vertex map - std::string name; - GetS0(name, length); - - switch (type) { - case AI_LWO_TXUV: - if (dims != 2) { - ASSIMP_LOG_WARN("LWO2: Skipping UV channel \'", name, "\' with !2 components"); - return; - } - base = FindEntry(mCurLayer->mUVChannels, name, perPoly); - break; - case AI_LWO_WGHT: - case AI_LWO_MNVW: - if (dims != 1) { - ASSIMP_LOG_WARN("LWO2: Skipping Weight Channel \'", name, "\' with !1 components"); - return; - } - base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels : mCurLayer->mSWeightChannels), name, perPoly); - break; - case AI_LWO_RGB: - case AI_LWO_RGBA: - if (dims != 3 && dims != 4) { - ASSIMP_LOG_WARN("LWO2: Skipping Color Map \'", name, "\' with a dimension > 4 or < 3"); - return; - } - base = FindEntry(mCurLayer->mVColorChannels, name, perPoly); - break; - - case AI_LWO_MODO_NORM: - /* This is a non-standard extension chunk used by Luxology's MODO. - * It stores per-vertex normals. This VMAP exists just once, has - * 3 dimensions and is btw extremely beautiful. - */ - if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length()) - return; - - ASSIMP_LOG_INFO("Processing non-standard extension: MODO VMAP.NORM.vert_normals"); - - mCurLayer->mNormals.name = name; - base = &mCurLayer->mNormals; - break; - - case AI_LWO_PICK: /* these VMAPs are just silently dropped */ - case AI_LWO_MORF: - case AI_LWO_SPOT: - return; - - default: - if (name == "APS.Level") { - // XXX handle this (seems to be subdivision-related). - } - ASSIMP_LOG_WARN("LWO2: Skipping unknown VMAP/VMAD channel \'", name, "\'"); - return; - }; - base->Allocate((unsigned int)mCurLayer->mTempPoints.size()); - - // now read all entries in the map - type = std::min(dims, base->dims); - const unsigned int diff = (dims - type) << 2u; - - LWO::FaceList &list = mCurLayer->mFaces; - LWO::PointList &pointList = mCurLayer->mTempPoints; - LWO::ReferrerList &refList = mCurLayer->mPointReferrers; - - const unsigned int numPoints = (unsigned int)pointList.size(); - const unsigned int numFaces = (unsigned int)list.size(); - - while (mFileBuffer < end) { - - unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs; - if (idx >= numPoints) { - ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAP/VMAD entry \'", name, "\', vertex index is out of range"); - mFileBuffer += base->dims << 2u; - continue; - } - if (perPoly) { - unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs; - if (base->abAssigned[idx]) { - // we have already a VMAP entry for this vertex - thus - // we need to duplicate the corresponding polygon. - if (polyIdx >= numFaces) { - ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAD entry \'", name, "\', polygon index is out of range"); - mFileBuffer += base->dims << 2u; - continue; - } - - LWO::Face &src = list[polyIdx]; - - // generate a new unique vertex for the corresponding index - but only - // if we can find the index in the face - bool had = false; - for (unsigned int i = 0; i < src.mNumIndices; ++i) { - - unsigned int srcIdx = src.mIndices[i], tmp = idx; - do { - if (tmp == srcIdx) - break; - } while ((tmp = refList[tmp]) != UINT_MAX); - if (tmp == UINT_MAX) { - continue; - } - - had = true; - refList.resize(refList.size() + 1, UINT_MAX); - - idx = (unsigned int)pointList.size(); - src.mIndices[i] = (unsigned int)pointList.size(); - - // store the index of the new vertex in the old vertex - // so we get a single linked list we can traverse in - // only one direction - AddToSingleLinkedList(refList, srcIdx, src.mIndices[i]); - pointList.push_back(pointList[srcIdx]); - - CreateNewEntry(mCurLayer->mVColorChannels, srcIdx); - CreateNewEntry(mCurLayer->mUVChannels, srcIdx); - CreateNewEntry(mCurLayer->mWeightChannels, srcIdx); - CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx); - CreateNewEntry(mCurLayer->mNormals, srcIdx); - } - if (!had) { - ASSIMP_LOG_WARN("LWO2: Failure evaluating VMAD entry \'", name, "\', vertex index wasn't found in that polygon"); - ai_assert(had); - } - } - } - - std::unique_ptr temp(new float[type]); - for (unsigned int l = 0; l < type; ++l) - temp[l] = GetF4(); - - DoRecursiveVMAPAssignment(base, type, idx, temp.get()); - mFileBuffer += diff; - } -} - -// ------------------------------------------------------------------------------------------------ -// Load LWO2 clip -void LWOImporter::LoadLWO2Clip(unsigned int length) { - AI_LWO_VALIDATE_CHUNK_LENGTH(length, CLIP, 10); - - mClips.push_back(LWO::Clip()); - LWO::Clip &clip = mClips.back(); - - // first - get the index of the clip - clip.idx = GetU4(); - - IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - switch (head.type) { - case AI_LWO_STIL: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, STIL, 1); - - // "Normal" texture - GetS0(clip.path, head.length); - clip.type = Clip::STILL; - break; - - case AI_LWO_ISEQ: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ISEQ, 16); - // Image sequence. We'll later take the first. - { - uint8_t digits = GetU1(); - mFileBuffer++; - int16_t offset = GetU2(); - mFileBuffer += 4; - int16_t start = GetU2(); - mFileBuffer += 4; - - std::string s; - std::ostringstream ss; - GetS0(s, head.length); - - head.length -= (uint16_t)s.length() + 1; - ss << s; - ss << std::setw(digits) << offset + start; - GetS0(s, head.length); - ss << s; - clip.path = ss.str(); - clip.type = Clip::SEQ; - } - break; - - case AI_LWO_STCC: - ASSIMP_LOG_WARN("LWO2: Color shifted images are not supported"); - break; - - case AI_LWO_ANIM: - ASSIMP_LOG_WARN("LWO2: Animated textures are not supported"); - break; - - case AI_LWO_XREF: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, XREF, 4); - - // Just a cross-reference to another CLIp - clip.type = Clip::REF; - clip.clipRef = GetU4(); - break; - - case AI_LWO_NEGA: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, NEGA, 2); - clip.negate = (0 != GetU2()); - break; - - default: - ASSIMP_LOG_WARN("LWO2: Encountered unknown CLIP sub-chunk"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Load envelope description -void LWOImporter::LoadLWO2Envelope(unsigned int length) { - LE_NCONST uint8_t *const end = mFileBuffer + length; - AI_LWO_VALIDATE_CHUNK_LENGTH(length, ENVL, 4); - - mEnvelopes.push_back(LWO::Envelope()); - LWO::Envelope &envelope = mEnvelopes.back(); - - // Get the index of the envelope - envelope.index = ReadVSizedIntLWO2(mFileBuffer); - - // It looks like there might be an extra U4 right after the index, - // at least in modo (LXOB) files: we'll ignore it if it's zero, - // otherwise it represents the start of a subchunk, so we backtrack. - if (mIsLXOB) { - uint32_t extra = GetU4(); - if (extra) { - mFileBuffer -= 4; - } - } - - // ... and read all subchunks - while (true) { - if (mFileBuffer + 6 >= end) break; - LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - throw DeadlyImportError("LWO2: Invalid envelope chunk length"); - - uint8_t *const next = mFileBuffer + head.length; - switch (head.type) { - // Type & representation of the envelope - case AI_LWO_TYPE: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TYPE, 2); - mFileBuffer++; // skip user format - - // Determine type of envelope - envelope.type = (LWO::EnvelopeType)*mFileBuffer; - ++mFileBuffer; - break; - - // precondition - case AI_LWO_PRE: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, PRE, 2); - envelope.pre = (LWO::PrePostBehaviour)GetU2(); - break; - - // postcondition - case AI_LWO_POST: - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, POST, 2); - envelope.post = (LWO::PrePostBehaviour)GetU2(); - break; - - // keyframe - case AI_LWO_KEY: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, KEY, 8); - - envelope.keys.push_back(LWO::Key()); - LWO::Key &key = envelope.keys.back(); - - key.time = GetF4(); - key.value = GetF4(); - break; - } - - // interval interpolation - case AI_LWO_SPAN: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPAN, 4); - if (envelope.keys.size() < 2) - ASSIMP_LOG_WARN("LWO2: Unexpected SPAN chunk"); - else { - LWO::Key &key = envelope.keys.back(); - switch (GetU4()) { - case AI_LWO_STEP: - key.inter = LWO::IT_STEP; - break; - case AI_LWO_LINE: - key.inter = LWO::IT_LINE; - break; - case AI_LWO_TCB: - key.inter = LWO::IT_TCB; - break; - case AI_LWO_HERM: - key.inter = LWO::IT_HERM; - break; - case AI_LWO_BEZI: - key.inter = LWO::IT_BEZI; - break; - case AI_LWO_BEZ2: - key.inter = LWO::IT_BEZ2; - break; - default: - ASSIMP_LOG_WARN("LWO2: Unknown interval interpolation mode"); - }; - - // todo ... read params - } - break; - } - - default: - ASSIMP_LOG_WARN("LWO2: Encountered unknown ENVL subchunk"); - break; - } - // regardless how much we did actually read, go to the next chunk - mFileBuffer = next; - } -} - -// ------------------------------------------------------------------------------------------------ -// Load file - master function -void LWOImporter::LoadLWO2File() { - bool skip = false; - - LE_NCONST uint8_t *const end = mFileBuffer + fileSize; - unsigned int iUnnamed = 0; - while (true) { - if (mFileBuffer + sizeof(IFF::ChunkHeader) > end) break; - const IFF::ChunkHeader head = IFF::LoadChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) { - throw DeadlyImportError("LWO2: Chunk length points behind the file"); - break; - } - uint8_t *const next = mFileBuffer + head.length; - - if (!head.length) { - mFileBuffer = next; - continue; - } - - switch (head.type) { - // new layer - case AI_LWO_LAYR: { - // add a new layer to the list .... - mLayers->push_back(LWO::Layer()); - LWO::Layer &layer = mLayers->back(); - mCurLayer = &layer; - - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LAYR, 16); - - // layer index. - layer.mIndex = GetU2(); - - // Continue loading this layer or ignore it? Check the layer index property - if (UINT_MAX != configLayerIndex && (configLayerIndex - 1) != layer.mIndex) { - skip = true; - } else - skip = false; - - // pivot point - mFileBuffer += 2; /* unknown */ - mCurLayer->mPivot.x = GetF4(); - mCurLayer->mPivot.y = GetF4(); - mCurLayer->mPivot.z = GetF4(); - GetS0(layer.mName, head.length - 16); - - // if the name is empty, generate a default name - if (layer.mName.empty()) { - char buffer[128]; // should be sufficiently large - ::ai_snprintf(buffer, 128, "Layer_%i", iUnnamed++); - layer.mName = buffer; - } - - // load this layer or ignore it? Check the layer name property - if (configLayerName.length() && configLayerName != layer.mName) { - skip = true; - } else - hasNamedLayer = true; - - // optional: parent of this layer - if (mFileBuffer + 2 <= next) - layer.mParent = GetU2(); - else - layer.mParent = (uint16_t) -1; - - // Set layer skip parameter - layer.skip = skip; - - break; - } - - // vertex list - case AI_LWO_PNTS: { - if (skip) - break; - - unsigned int old = (unsigned int)mCurLayer->mTempPoints.size(); - LoadLWOPoints(head.length); - mCurLayer->mPointIDXOfs = old; - break; - } - // vertex tags - case AI_LWO_VMAD: - if (mCurLayer->mFaces.empty()) { - ASSIMP_LOG_WARN("LWO2: Unexpected VMAD chunk"); - break; - } - // --- intentionally no break here - case AI_LWO_VMAP: { - if (skip) - break; - - if (mCurLayer->mTempPoints.empty()) - ASSIMP_LOG_WARN("LWO2: Unexpected VMAP chunk"); - else - LoadLWO2VertexMap(head.length, head.type == AI_LWO_VMAD); - break; - } - // face list - case AI_LWO_POLS: { - if (skip) - break; - - unsigned int old = (unsigned int)mCurLayer->mFaces.size(); - LoadLWO2Polygons(head.length); - mCurLayer->mFaceIDXOfs = old; - break; - } - // polygon tags - case AI_LWO_PTAG: { - if (skip) - break; - - if (mCurLayer->mFaces.empty()) { - ASSIMP_LOG_WARN("LWO2: Unexpected PTAG"); - } else { - LoadLWO2PolygonTags(head.length); - } - break; - } - // list of tags - case AI_LWO_TAGS: { - if (!mTags->empty()) { - ASSIMP_LOG_WARN("LWO2: SRFS chunk encountered twice"); - } else { - LoadLWOTags(head.length); - } - break; - } - - // surface chunk - case AI_LWO_SURF: { - LoadLWO2Surface(head.length); - break; - } - - // clip chunk - case AI_LWO_CLIP: { - LoadLWO2Clip(head.length); - break; - } - - // envelope chunk - case AI_LWO_ENVL: { - LoadLWO2Envelope(head.length); - break; - } - } - mFileBuffer = next; - } -} - -#endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER diff --git a/libs/assimp/code/AssetLib/LWO/LWOLoader.h b/libs/assimp/code/AssetLib/LWO/LWOLoader.h deleted file mode 100644 index f3add53..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOLoader.h +++ /dev/null @@ -1,468 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Declaration of the LWO importer class. */ -#pragma once -#ifndef AI_LWOLOADER_H_INCLUDED -#define AI_LWOLOADER_H_INCLUDED - -#include "LWOFileData.h" -#include -#include -#include - -#include - -struct aiTexture; -struct aiNode; -struct aiMaterial; - -namespace Assimp { -using namespace LWO; - -// --------------------------------------------------------------------------- -/** Class to load LWO files. - * - * @note Methods named "xxxLWO2[xxx]" are used with the newer LWO2 format. - * Methods named "xxxLWOB[xxx]" are used with the older LWOB format. - * Methods named "xxxLWO[xxx]" are used with both formats. - * Methods named "xxx" are used to preprocess the loaded data - - * they aren't specific to one format version -*/ -// --------------------------------------------------------------------------- -class LWOImporter : public BaseImporter { -public: - LWOImporter(); - ~LWOImporter() override; - - // ------------------------------------------------------------------- - /** Returns whether the class can handle the format of the given file. - * See BaseImporter::CanRead() for details. - */ - bool CanRead(const std::string &pFile, IOSystem *pIOHandler, - bool checkSig) const override; - - // ------------------------------------------------------------------- - /** Called prior to ReadFile(). - * The function is a request to the importer to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer *pImp) override; - -protected: - // ------------------------------------------------------------------- - // Get list of supported extensions - const aiImporterDesc *GetInfo() const override; - - // ------------------------------------------------------------------- - /** Imports the given file into the given scene structure. - * See BaseImporter::InternReadFile() for details - */ - void InternReadFile(const std::string &pFile, aiScene *pScene, - IOSystem *pIOHandler) override; - -private: - // ------------------------------------------------------------------- - /** Loads a LWO file in the older LWOB format (LW < 6) - */ - void LoadLWOBFile(); - - // ------------------------------------------------------------------- - /** Loads a LWO file in the newer LWO2 format (LW >= 6) - */ - void LoadLWO2File(); - - // ------------------------------------------------------------------- - /** Parsing functions used for all file format versions - */ - inline void GetS0(std::string &out, unsigned int max); - inline float GetF4(); - inline uint32_t GetU4(); - inline uint16_t GetU2(); - inline uint8_t GetU1(); - - // ------------------------------------------------------------------- - /** Loads a surface chunk from an LWOB file - * @param size Maximum size to be read, in bytes. - */ - void LoadLWOBSurface(unsigned int size); - - // ------------------------------------------------------------------- - /** Loads a surface chunk from an LWO2 file - * @param size Maximum size to be read, in bytes. - */ - void LoadLWO2Surface(unsigned int size); - - // ------------------------------------------------------------------- - /** Loads a texture block from a LWO2 file. - * @param size Maximum size to be read, in bytes. - * @param head Header of the SUF.BLOK header - */ - void LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head, - unsigned int size); - - // ------------------------------------------------------------------- - /** Loads a shader block from a LWO2 file. - * @param size Maximum size to be read, in bytes. - * @param head Header of the SUF.BLOK header - */ - void LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader *head, - unsigned int size); - - // ------------------------------------------------------------------- - /** Loads an image map from a LWO2 file - * @param size Maximum size to be read, in bytes. - * @param tex Texture object to be filled - */ - void LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex); - void LoadLWO2Gradient(unsigned int size, LWO::Texture &tex); - void LoadLWO2Procedural(unsigned int size, LWO::Texture &tex); - - // loads the header - used by thethree functions above - void LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex); - - // ------------------------------------------------------------------- - /** Loads the LWO tag list from the file - * @param size Maximum size to be read, in bytes. - */ - void LoadLWOTags(unsigned int size); - - // ------------------------------------------------------------------- - /** Load polygons from a POLS chunk - * @param length Size of the chunk - */ - void LoadLWO2Polygons(unsigned int length); - void LoadLWOBPolygons(unsigned int length); - - // ------------------------------------------------------------------- - /** Load polygon tags from a PTAG chunk - * @param length Size of the chunk - */ - void LoadLWO2PolygonTags(unsigned int length); - - // ------------------------------------------------------------------- - /** Load a vertex map from a VMAP/VMAD chunk - * @param length Size of the chunk - * @param perPoly Operate on per-polygon base? - */ - void LoadLWO2VertexMap(unsigned int length, bool perPoly); - - // ------------------------------------------------------------------- - /** Load polygons from a PNTS chunk - * @param length Size of the chunk - */ - void LoadLWOPoints(unsigned int length); - - // ------------------------------------------------------------------- - /** Load a clip from a CLIP chunk - * @param length Size of the chunk - */ - void LoadLWO2Clip(unsigned int length); - - // ------------------------------------------------------------------- - /** Load an envelope from an EVL chunk - * @param length Size of the chunk - */ - void LoadLWO2Envelope(unsigned int length); - - // ------------------------------------------------------------------- - /** Count vertices and faces in a LWOB/LWO2 file - */ - void CountVertsAndFacesLWO2(unsigned int &verts, - unsigned int &faces, - uint16_t *&cursor, - const uint16_t *const end, - unsigned int max = UINT_MAX); - - void CountVertsAndFacesLWOB(unsigned int &verts, - unsigned int &faces, - LE_NCONST uint16_t *&cursor, - const uint16_t *const end, - unsigned int max = UINT_MAX); - - // ------------------------------------------------------------------- - /** Read vertices and faces in a LWOB/LWO2 file - */ - void CopyFaceIndicesLWO2(LWO::FaceList::iterator &it, - uint16_t *&cursor, - const uint16_t *const end); - - // ------------------------------------------------------------------- - void CopyFaceIndicesLWOB(LWO::FaceList::iterator &it, - LE_NCONST uint16_t *&cursor, - const uint16_t *const end, - unsigned int max = UINT_MAX); - - // ------------------------------------------------------------------- - /** Resolve the tag and surface lists that have been loaded. - * Generates the mMapping table. - */ - void ResolveTags(); - - // ------------------------------------------------------------------- - /** Resolve the clip list that has been loaded. - * Replaces clip references with real clips. - */ - void ResolveClips(); - - // ------------------------------------------------------------------- - /** Add a texture list to an output material description. - * - * @param pcMat Output material - * @param in Input texture list - * @param type Type identifier of the texture list - */ - bool HandleTextures(aiMaterial *pcMat, const TextureList &in, - aiTextureType type); - - // ------------------------------------------------------------------- - /** Adjust a texture path - */ - void AdjustTexturePath(std::string &out); - - // ------------------------------------------------------------------- - /** Convert a LWO surface description to an ASSIMP material - */ - void ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat); - - // ------------------------------------------------------------------- - /** Get a list of all UV/VC channels required by a specific surface. - * - * @param surf Working surface - * @param layer Working layer - * @param out Output list. The members are indices into the - * UV/VC channel lists of the layer - */ - void FindUVChannels(/*const*/ LWO::Surface &surf, - LWO::SortedRep &sorted, - /*const*/ LWO::Layer &layer, - unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]); - - // ------------------------------------------------------------------- - char FindUVChannels(LWO::TextureList &list, - LWO::Layer &layer, LWO::UVChannel &uv, unsigned int next); - - // ------------------------------------------------------------------- - void FindVCChannels(const LWO::Surface &surf, - LWO::SortedRep &sorted, - const LWO::Layer &layer, - unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]); - - // ------------------------------------------------------------------- - /** Generate the final node graph - * Unused nodes are deleted. - * @param apcNodes Flat list of nodes - */ - void GenerateNodeGraph(std::map &apcNodes); - - // ------------------------------------------------------------------- - /** Add children to a node - * @param node Node to become a father - * @param parent Index of the node - * @param apcNodes Flat list of nodes - used nodes are set to nullptr. - */ - void AddChildren(aiNode *node, uint16_t parent, - std::vector &apcNodes); - - // ------------------------------------------------------------------- - /** Read a variable sized integer - * @param inout Input and output buffer - */ - int ReadVSizedIntLWO2(uint8_t *&inout); - - // ------------------------------------------------------------------- - /** Assign a value from a VMAP to a vertex and all vertices - * attached to it. - * @param base VMAP destination data - * @param numRead Number of float's to be read - * @param idx Absolute index of the first vertex - * @param data Value of the VMAP to be assigned - read numRead - * floats from this array. - */ - void DoRecursiveVMAPAssignment(VMapEntry *base, unsigned int numRead, - unsigned int idx, float *data); - - // ------------------------------------------------------------------- - /** Compute normal vectors for a mesh - * @param mesh Input mesh - * @param smoothingGroups Smoothing-groups-per-face array - * @param surface Surface for the mesh - */ - void ComputeNormals(aiMesh *mesh, const std::vector &smoothingGroups, - const LWO::Surface &surface); - - // ------------------------------------------------------------------- - /** Setup a new texture after the corresponding chunk was - * encountered in the file. - * @param list Texture list - * @param size Maximum number of bytes to be read - * @return Pointer to new texture - */ - LWO::Texture *SetupNewTextureLWOB(LWO::TextureList &list, - unsigned int size); - -protected: - /** true if the file is a LWO2 file*/ - bool mIsLWO2; - - /** true if the file is a LXOB file*/ - bool mIsLXOB; - - /** Temporary list of layers from the file */ - LayerList *mLayers; - - /** Pointer to the current layer */ - LWO::Layer *mCurLayer; - - /** Temporary tag list from the file */ - TagList *mTags; - - /** Mapping table to convert from tag to surface indices. - UINT_MAX indicates that a no corresponding surface is available */ - TagMappingTable *mMapping; - - /** Temporary surface list from the file */ - SurfaceList *mSurfaces; - - /** Temporary clip list from the file */ - ClipList mClips; - - /** Temporary envelope list from the file */ - EnvelopeList mEnvelopes; - - /** file buffer */ - uint8_t *mFileBuffer; - - /** Size of the file, in bytes */ - unsigned int fileSize; - - /** Output scene */ - aiScene *mScene; - - /** Configuration option: speed flag set? */ - bool configSpeedFlag; - - /** Configuration option: index of layer to be loaded */ - unsigned int configLayerIndex; - - /** Configuration option: name of layer to be loaded */ - std::string configLayerName; - - /** True if we have a named layer */ - bool hasNamedLayer; -}; - -// ------------------------------------------------------------------------------------------------ -inline float LWOImporter::GetF4() { - float f; - ::memcpy(&f, mFileBuffer, 4); - mFileBuffer += 4; - AI_LSWAP4(f); - return f; -} - -// ------------------------------------------------------------------------------------------------ -inline uint32_t LWOImporter::GetU4() { - uint32_t f; - ::memcpy(&f, mFileBuffer, 4); - mFileBuffer += 4; - AI_LSWAP4(f); - return f; -} - -// ------------------------------------------------------------------------------------------------ -inline uint16_t LWOImporter::GetU2() { - uint16_t f; - ::memcpy(&f, mFileBuffer, 2); - mFileBuffer += 2; - AI_LSWAP2(f); - return f; -} - -// ------------------------------------------------------------------------------------------------ -inline uint8_t LWOImporter::GetU1() { - return *mFileBuffer++; -} - -// ------------------------------------------------------------------------------------------------ -inline int LWOImporter::ReadVSizedIntLWO2(uint8_t *&inout) { - int i; - int c = *inout; - inout++; - if (c != 0xFF) { - i = c << 8; - c = *inout; - inout++; - i |= c; - } else { - c = *inout; - inout++; - i = c << 16; - c = *inout; - inout++; - i |= c << 8; - c = *inout; - inout++; - i |= c; - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -inline void LWOImporter::GetS0(std::string &out, unsigned int max) { - unsigned int iCursor = 0; - const char *sz = (const char *)mFileBuffer; - while (*mFileBuffer) { - if (++iCursor > max) { - ASSIMP_LOG_WARN("LWO: Invalid file, string is is too long"); - break; - } - ++mFileBuffer; - } - size_t len = (size_t)((const char *)mFileBuffer - sz); - out = std::string(sz, len); - mFileBuffer += (len & 0x1 ? 1 : 2); -} - -} // end of namespace Assimp - -#endif // AI_LWOIMPORTER_H_INCLUDED diff --git a/libs/assimp/code/AssetLib/LWO/LWOMaterial.cpp b/libs/assimp/code/AssetLib/LWO/LWOMaterial.cpp deleted file mode 100644 index b6f0bcc..0000000 --- a/libs/assimp/code/AssetLib/LWO/LWOMaterial.cpp +++ /dev/null @@ -1,844 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2022, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the material oart of the LWO importer class */ - -#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER - -// internal headers -#include "LWOLoader.h" -#include - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -template -T lerp(const T &one, const T &two, float val) { - return one + (two - one) * val; -} - -// ------------------------------------------------------------------------------------------------ -// Convert a lightwave mapping mode to our's -inline aiTextureMapMode GetMapMode(LWO::Texture::Wrap in) { - switch (in) { - case LWO::Texture::REPEAT: - return aiTextureMapMode_Wrap; - - case LWO::Texture::MIRROR: - return aiTextureMapMode_Mirror; - - case LWO::Texture::RESET: - ASSIMP_LOG_WARN("LWO2: Unsupported texture map mode: RESET"); - - // fall though here - case LWO::Texture::EDGE: - return aiTextureMapMode_Clamp; - } - return (aiTextureMapMode)0; -} - -// ------------------------------------------------------------------------------------------------ -bool LWOImporter::HandleTextures(aiMaterial *pcMat, const TextureList &in, aiTextureType type) { - ai_assert(nullptr != pcMat); - - unsigned int cur = 0, temp = 0; - aiString s; - bool ret = false; - - for (const auto &texture : in) { - if (!texture.enabled || !texture.bCanUse) - continue; - ret = true; - - // Convert lightwave's mapping modes to ours. We let them - // as they are, the GenUVcoords step will compute UV - // channels if they're not there. - - aiTextureMapping mapping = aiTextureMapping_OTHER; - switch (texture.mapMode) { - case LWO::Texture::Planar: - mapping = aiTextureMapping_PLANE; - break; - case LWO::Texture::Cylindrical: - mapping = aiTextureMapping_CYLINDER; - break; - case LWO::Texture::Spherical: - mapping = aiTextureMapping_SPHERE; - break; - case LWO::Texture::Cubic: - mapping = aiTextureMapping_BOX; - break; - case LWO::Texture::FrontProjection: - ASSIMP_LOG_ERROR("LWO2: Unsupported texture mapping: FrontProjection"); - mapping = aiTextureMapping_OTHER; - break; - case LWO::Texture::UV: { - if (UINT_MAX == texture.mRealUVIndex) { - // We have no UV index for this texture, so we can't display it - continue; - } - - // add the UV source index - temp = texture.mRealUVIndex; - pcMat->AddProperty((int *)&temp, 1, AI_MATKEY_UVWSRC(type, cur)); - - mapping = aiTextureMapping_UV; - } break; - default: - ai_assert(false); - }; - - if (mapping != aiTextureMapping_UV) { - // Setup the main axis - aiVector3D v; - switch (texture.majorAxis) { - case Texture::AXIS_X: - v = aiVector3D(1.0, 0.0, 0.0); - break; - case Texture::AXIS_Y: - v = aiVector3D(0.0, 1.0, 0.0); - break; - default: // case Texture::AXIS_Z: - v = aiVector3D(0.0, 0.0, 1.0); - break; - } - - pcMat->AddProperty(&v, 1, AI_MATKEY_TEXMAP_AXIS(type, cur)); - - // Setup UV scalings for cylindric and spherical projections - if (mapping == aiTextureMapping_CYLINDER || mapping == aiTextureMapping_SPHERE) { - aiUVTransform trafo; - trafo.mScaling.x = texture.wrapAmountW; - trafo.mScaling.y = texture.wrapAmountH; - - static_assert(sizeof(aiUVTransform) / sizeof(ai_real) == 5, "sizeof(aiUVTransform)/sizeof(ai_real) == 5"); - pcMat->AddProperty(&trafo, 1, AI_MATKEY_UVTRANSFORM(type, cur)); - } - ASSIMP_LOG_VERBOSE_DEBUG("LWO2: Setting up non-UV mapping"); - } - - // The older LWOB format does not use indirect references to clips. - // The file name of a texture is directly specified in the tex chunk. - if (mIsLWO2) { - // find the corresponding clip (take the last one if multiple - // share the same index) - ClipList::iterator end = mClips.end(), candidate = end; - temp = texture.mClipIdx; - for (ClipList::iterator clip = mClips.begin(); clip != end; ++clip) { - if ((*clip).idx == temp) { - candidate = clip; - } - } - if (candidate == end) { - ASSIMP_LOG_ERROR("LWO2: Clip index is out of bounds"); - temp = 0; - - // fixme: apparently some LWO files shipping with Doom3 don't - // have clips at all ... check whether that's true or whether - // it's a bug in the loader. - - s.Set("$texture.png"); - - //continue; - } else { - if (Clip::UNSUPPORTED == (*candidate).type) { - ASSIMP_LOG_ERROR("LWO2: Clip type is not supported"); - continue; - } - AdjustTexturePath((*candidate).path); - s.Set((*candidate).path); - - // Additional image settings - int flags = 0; - if ((*candidate).negate) { - flags |= aiTextureFlags_Invert; - } - pcMat->AddProperty(&flags, 1, AI_MATKEY_TEXFLAGS(type, cur)); - } - } else { - std::string ss = texture.mFileName; - if (!ss.length()) { - ASSIMP_LOG_WARN("LWOB: Empty file name"); - continue; - } - AdjustTexturePath(ss); - s.Set(ss); - } - pcMat->AddProperty(&s, AI_MATKEY_TEXTURE(type, cur)); - - // add the blend factor - pcMat->AddProperty(&texture.mStrength, 1, AI_MATKEY_TEXBLEND(type, cur)); - - // add the blend operation - switch (texture.blendType) { - case LWO::Texture::Normal: - case LWO::Texture::Multiply: - temp = (unsigned int)aiTextureOp_Multiply; - break; - - case LWO::Texture::Subtractive: - case LWO::Texture::Difference: - temp = (unsigned int)aiTextureOp_Subtract; - break; - - case LWO::Texture::Divide: - temp = (unsigned int)aiTextureOp_Divide; - break; - - case LWO::Texture::Additive: - temp = (unsigned int)aiTextureOp_Add; - break; - - default: - temp = (unsigned int)aiTextureOp_Multiply; - ASSIMP_LOG_WARN("LWO2: Unsupported texture blend mode: alpha or displacement"); - } - // Setup texture operation - pcMat->AddProperty((int *)&temp, 1, AI_MATKEY_TEXOP(type, cur)); - - // setup the mapping mode - int mapping_ = static_cast(mapping); - pcMat->AddProperty(&mapping_, 1, AI_MATKEY_MAPPING(type, cur)); - - // add the u-wrapping - temp = (unsigned int)GetMapMode(texture.wrapModeWidth); - pcMat->AddProperty((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_U(type, cur)); - - // add the v-wrapping - temp = (unsigned int)GetMapMode(texture.wrapModeHeight); - pcMat->AddProperty((int *)&temp, 1, AI_MATKEY_MAPPINGMODE_V(type, cur)); - - ++cur; - } - return ret; -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::ConvertMaterial(const LWO::Surface &surf, aiMaterial *pcMat) { - // copy the name of the surface - aiString st; - st.Set(surf.mName); - pcMat->AddProperty(&st, AI_MATKEY_NAME); - - const int i = surf.bDoubleSided ? 1 : 0; - pcMat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED); - - // add the refraction index and the bump intensity - pcMat->AddProperty(&surf.mIOR, 1, AI_MATKEY_REFRACTI); - pcMat->AddProperty(&surf.mBumpIntensity, 1, AI_MATKEY_BUMPSCALING); - - aiShadingMode m; - if (surf.mSpecularValue && surf.mGlossiness) { - float fGloss; - if (mIsLWO2) { - fGloss = std::pow(surf.mGlossiness * ai_real(10.0) + ai_real(2.0), ai_real(2.0)); - } else { - if (16.0 >= surf.mGlossiness) - fGloss = 6.0; - else if (64.0 >= surf.mGlossiness) - fGloss = 20.0; - else if (256.0 >= surf.mGlossiness) - fGloss = 50.0; - else - fGloss = 80.0; - } - - pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH); - pcMat->AddProperty(&fGloss, 1, AI_MATKEY_SHININESS); - m = aiShadingMode_Phong; - } else - m = aiShadingMode_Gouraud; - - // specular color - aiColor3D clr = lerp(aiColor3D(1.0, 1.0, 1.0), surf.mColor, surf.mColorHighlights); - pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); - pcMat->AddProperty(&surf.mSpecularValue, 1, AI_MATKEY_SHININESS_STRENGTH); - - // emissive color - // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good. - clr.g = clr.b = clr.r = surf.mLuminosity * ai_real(0.8); - pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_EMISSIVE); - - // opacity ... either additive or default-blended, please - if (0.0 != surf.mAdditiveTransparency) { - const int add = aiBlendMode_Additive; - pcMat->AddProperty(&surf.mAdditiveTransparency, 1, AI_MATKEY_OPACITY); - pcMat->AddProperty(&add, 1, AI_MATKEY_BLEND_FUNC); - } else if (10e10f != surf.mTransparency) { - const int def = aiBlendMode_Default; - const float f = 1.0f - surf.mTransparency; - pcMat->AddProperty(&f, 1, AI_MATKEY_OPACITY); - pcMat->AddProperty(&def, 1, AI_MATKEY_BLEND_FUNC); - } - - // ADD TEXTURES to the material - // TODO: find out how we can handle COLOR textures correctly... - bool b = HandleTextures(pcMat, surf.mColorTextures, aiTextureType_DIFFUSE); - b = (b || HandleTextures(pcMat, surf.mDiffuseTextures, aiTextureType_DIFFUSE)); - HandleTextures(pcMat, surf.mSpecularTextures, aiTextureType_SPECULAR); - HandleTextures(pcMat, surf.mGlossinessTextures, aiTextureType_SHININESS); - HandleTextures(pcMat, surf.mBumpTextures, aiTextureType_HEIGHT); - HandleTextures(pcMat, surf.mOpacityTextures, aiTextureType_OPACITY); - HandleTextures(pcMat, surf.mReflectionTextures, aiTextureType_REFLECTION); - - // Now we need to know which shader to use .. iterate through the shader list of - // the surface and search for a name which we know ... - for (const auto &shader : surf.mShaders) { - if (shader.functionName == "LW_SuperCelShader" || shader.functionName == "AH_CelShader") { - ASSIMP_LOG_INFO("LWO2: Mapping LW_SuperCelShader/AH_CelShader to aiShadingMode_Toon"); - - m = aiShadingMode_Toon; - break; - } else if (shader.functionName == "LW_RealFresnel" || shader.functionName == "LW_FastFresnel") { - ASSIMP_LOG_INFO("LWO2: Mapping LW_RealFresnel/LW_FastFresnel to aiShadingMode_Fresnel"); - - m = aiShadingMode_Fresnel; - break; - } else { - ASSIMP_LOG_WARN("LWO2: Unknown surface shader: ", shader.functionName); - } - } - if (surf.mMaximumSmoothAngle <= 0.0) - m = aiShadingMode_Flat; - int m_ = static_cast(m); - pcMat->AddProperty(&m_, 1, AI_MATKEY_SHADING_MODEL); - - // (the diffuse value is just a scaling factor) - // If a diffuse texture is set, we set this value to 1.0 - clr = (b && false ? aiColor3D(1.0, 1.0, 1.0) : surf.mColor); - clr.r *= surf.mDiffuseValue; - clr.g *= surf.mDiffuseValue; - clr.b *= surf.mDiffuseValue; - pcMat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); -} - -// ------------------------------------------------------------------------------------------------ -char LWOImporter::FindUVChannels(LWO::TextureList &list, - LWO::Layer & /*layer*/, LWO::UVChannel &uv, unsigned int next) { - char ret = 0; - for (auto &texture : list) { - - // Ignore textures with non-UV mappings for the moment. - if (!texture.enabled || !texture.bCanUse || texture.mapMode != LWO::Texture::UV) { - continue; - } - - if (texture.mUVChannelIndex == uv.name) { - ret = 1; - - // got it. - if (texture.mRealUVIndex == UINT_MAX || texture.mRealUVIndex == next) { - texture.mRealUVIndex = next; - } else { - // channel mismatch. need to duplicate the material. - ASSIMP_LOG_WARN("LWO: Channel mismatch, would need to duplicate surface [design bug]"); - - // TODO - } - } - } - return ret; -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::FindUVChannels(LWO::Surface &surf, - LWO::SortedRep &sorted, LWO::Layer &layer, - unsigned int out[AI_MAX_NUMBER_OF_TEXTURECOORDS]) { - unsigned int next = 0, extra = 0, num_extra = 0; - - // Check whether we have an UV entry != 0 for one of the faces in 'sorted' - for (unsigned int i = 0; i < layer.mUVChannels.size(); ++i) { - LWO::UVChannel &uv = layer.mUVChannels[i]; - - for (LWO::SortedRep::const_iterator it = sorted.begin(); it != sorted.end(); ++it) { - - LWO::Face &face = layer.mFaces[*it]; - - for (unsigned int n = 0; n < face.mNumIndices; ++n) { - unsigned int idx = face.mIndices[n]; - - if (uv.abAssigned[idx] && ((aiVector2D *)&uv.rawData[0])[idx] != aiVector2D()) { - - if (extra >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { - - ASSIMP_LOG_ERROR("LWO: Maximum number of UV channels for " - "this mesh reached. Skipping channel \'" + - uv.name + "\'"); - - } else { - // Search through all textures assigned to 'surf' and look for this UV channel - char had = 0; - had |= FindUVChannels(surf.mColorTextures, layer, uv, next); - had |= FindUVChannels(surf.mDiffuseTextures, layer, uv, next); - had |= FindUVChannels(surf.mSpecularTextures, layer, uv, next); - had |= FindUVChannels(surf.mGlossinessTextures, layer, uv, next); - had |= FindUVChannels(surf.mOpacityTextures, layer, uv, next); - had |= FindUVChannels(surf.mBumpTextures, layer, uv, next); - had |= FindUVChannels(surf.mReflectionTextures, layer, uv, next); - - // We have a texture referencing this UV channel so we have to take special care - // and are willing to drop unreferenced channels in favour of it. - if (had != 0) { - if (num_extra) { - - for (unsigned int a = next; a < std::min(extra, AI_MAX_NUMBER_OF_TEXTURECOORDS - 1u); ++a) { - out[a + 1] = out[a]; - } - } - ++extra; - out[next++] = i; - } - // Bah ... seems not to be used at all. Push to end if enough space is available. - else { - out[extra++] = i; - ++num_extra; - } - } - it = sorted.end() - 1; - break; - } - } - } - } - if (extra < AI_MAX_NUMBER_OF_TEXTURECOORDS) { - out[extra] = UINT_MAX; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::FindVCChannels(const LWO::Surface &surf, LWO::SortedRep &sorted, const LWO::Layer &layer, - unsigned int out[AI_MAX_NUMBER_OF_COLOR_SETS]) { - unsigned int next = 0; - - // Check whether we have an vc entry != 0 for one of the faces in 'sorted' - for (unsigned int i = 0; i < layer.mVColorChannels.size(); ++i) { - const LWO::VColorChannel &vc = layer.mVColorChannels[i]; - - if (surf.mVCMap == vc.name) { - // The vertex color map is explicitly requested by the surface so we need to take special care of it - for (unsigned int a = 0; a < std::min(next, AI_MAX_NUMBER_OF_COLOR_SETS - 1u); ++a) { - out[a + 1] = out[a]; - } - out[0] = i; - ++next; - } else { - - for (LWO::SortedRep::iterator it = sorted.begin(); it != sorted.end(); ++it) { - const LWO::Face &face = layer.mFaces[*it]; - - for (unsigned int n = 0; n < face.mNumIndices; ++n) { - unsigned int idx = face.mIndices[n]; - - if (vc.abAssigned[idx] && ((aiColor4D *)&vc.rawData[0])[idx] != aiColor4D(0.0, 0.0, 0.0, 1.0)) { - if (next >= AI_MAX_NUMBER_OF_COLOR_SETS) { - - ASSIMP_LOG_ERROR("LWO: Maximum number of vertex color channels for " - "this mesh reached. Skipping channel \'" + - vc.name + "\'"); - - } else { - out[next++] = i; - } - it = sorted.end() - 1; - break; - } - } - } - } - } - if (next != AI_MAX_NUMBER_OF_COLOR_SETS) { - out[next] = UINT_MAX; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2ImageMap(unsigned int size, LWO::Texture &tex) { - LE_NCONST uint8_t *const end = mFileBuffer + size; - while (true) { - if (mFileBuffer + 6 >= end) break; - LE_NCONST IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - throw DeadlyImportError("LWO2: Invalid SURF.BLOCK chunk length"); - - uint8_t *const next = mFileBuffer + head.length; - switch (head.type) { - case AI_LWO_PROJ: - tex.mapMode = (Texture::MappingMode)GetU2(); - break; - case AI_LWO_WRAP: - tex.wrapModeWidth = (Texture::Wrap)GetU2(); - tex.wrapModeHeight = (Texture::Wrap)GetU2(); - break; - case AI_LWO_AXIS: - tex.majorAxis = (Texture::Axes)GetU2(); - break; - case AI_LWO_IMAG: - tex.mClipIdx = GetU2(); - break; - case AI_LWO_VMAP: - GetS0(tex.mUVChannelIndex, head.length); - break; - case AI_LWO_WRPH: - tex.wrapAmountH = GetF4(); - break; - case AI_LWO_WRPW: - tex.wrapAmountW = GetF4(); - break; - } - mFileBuffer = next; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2Procedural(unsigned int /*size*/, LWO::Texture &tex) { - // --- not supported at the moment - ASSIMP_LOG_ERROR("LWO2: Found procedural texture, this is not supported"); - tex.bCanUse = false; -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2Gradient(unsigned int /*size*/, LWO::Texture &tex) { - // --- not supported at the moment - ASSIMP_LOG_ERROR("LWO2: Found gradient texture, this is not supported"); - tex.bCanUse = false; -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2TextureHeader(unsigned int size, LWO::Texture &tex) { - LE_NCONST uint8_t *const end = mFileBuffer + size; - - // get the ordinal string - GetS0(tex.ordinal, size); - - // we could crash later if this is an empty string ... - if (!tex.ordinal.length()) { - ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string"); - tex.ordinal = "\x00"; - } - while (true) { - if (mFileBuffer + 6 >= end) break; - const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - throw DeadlyImportError("LWO2: Invalid texture header chunk length"); - - uint8_t *const next = mFileBuffer + head.length; - switch (head.type) { - case AI_LWO_CHAN: - tex.type = GetU4(); - break; - case AI_LWO_ENAB: - tex.enabled = GetU2() ? true : false; - break; - case AI_LWO_OPAC: - tex.blendType = (Texture::BlendType)GetU2(); - tex.mStrength = GetF4(); - break; - } - mFileBuffer = next; - } -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2TextureBlock(LE_NCONST IFF::SubChunkHeader *head, unsigned int size) { - ai_assert(!mSurfaces->empty()); - LWO::Surface &surf = mSurfaces->back(); - LWO::Texture tex; - - // load the texture header - LoadLWO2TextureHeader(head->length, tex); - size -= head->length + 6; - - // now get the exact type of the texture - switch (head->type) { - case AI_LWO_PROC: - LoadLWO2Procedural(size, tex); - break; - case AI_LWO_GRAD: - LoadLWO2Gradient(size, tex); - break; - case AI_LWO_IMAP: - LoadLWO2ImageMap(size, tex); - } - - // get the destination channel - TextureList *listRef = nullptr; - switch (tex.type) { - case AI_LWO_COLR: - listRef = &surf.mColorTextures; - break; - case AI_LWO_DIFF: - listRef = &surf.mDiffuseTextures; - break; - case AI_LWO_SPEC: - listRef = &surf.mSpecularTextures; - break; - case AI_LWO_GLOS: - listRef = &surf.mGlossinessTextures; - break; - case AI_LWO_BUMP: - listRef = &surf.mBumpTextures; - break; - case AI_LWO_TRAN: - listRef = &surf.mOpacityTextures; - break; - case AI_LWO_REFL: - listRef = &surf.mReflectionTextures; - break; - default: - ASSIMP_LOG_WARN("LWO2: Encountered unknown texture type"); - return; - } - - // now attach the texture to the parent surface - sort by ordinal string - for (TextureList::iterator it = listRef->begin(); it != listRef->end(); ++it) { - if (::strcmp(tex.ordinal.c_str(), (*it).ordinal.c_str()) < 0) { - listRef->insert(it, tex); - return; - } - } - listRef->push_back(tex); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2ShaderBlock(LE_NCONST IFF::SubChunkHeader * /*head*/, unsigned int size) { - LE_NCONST uint8_t *const end = mFileBuffer + size; - - ai_assert(!mSurfaces->empty()); - LWO::Surface &surf = mSurfaces->back(); - LWO::Shader shader; - - // get the ordinal string - GetS0(shader.ordinal, size); - - // we could crash later if this is an empty string ... - if (!shader.ordinal.length()) { - ASSIMP_LOG_ERROR("LWO2: Ill-formed SURF.BLOK ordinal string"); - shader.ordinal = "\x00"; - } - - // read the header - while (true) { - if (mFileBuffer + 6 >= end) break; - const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - throw DeadlyImportError("LWO2: Invalid shader header chunk length"); - - uint8_t *const next = mFileBuffer + head.length; - switch (head.type) { - case AI_LWO_ENAB: - shader.enabled = GetU2() ? true : false; - break; - - case AI_LWO_FUNC: - GetS0(shader.functionName, head.length); - } - mFileBuffer = next; - } - - // now attach the shader to the parent surface - sort by ordinal string - for (ShaderList::iterator it = surf.mShaders.begin(); it != surf.mShaders.end(); ++it) { - if (::strcmp(shader.ordinal.c_str(), (*it).ordinal.c_str()) < 0) { - surf.mShaders.insert(it, shader); - return; - } - } - surf.mShaders.push_back(shader); -} - -// ------------------------------------------------------------------------------------------------ -void LWOImporter::LoadLWO2Surface(unsigned int size) { - LE_NCONST uint8_t *const end = mFileBuffer + size; - - mSurfaces->push_back(LWO::Surface()); - LWO::Surface &surf = mSurfaces->back(); - - GetS0(surf.mName, size); - - // check whether this surface was derived from any other surface - std::string derived; - GetS0(derived, (unsigned int)(end - mFileBuffer)); - if (derived.length()) { - // yes, find this surface - for (SurfaceList::iterator it = mSurfaces->begin(), itEnd = mSurfaces->end() - 1; it != itEnd; ++it) { - if ((*it).mName == derived) { - // we have it ... - surf = *it; - derived.clear(); - break; - } - } - if (derived.size()) { - ASSIMP_LOG_WARN("LWO2: Unable to find source surface: ", derived); - } - } - - while (true) { - if (mFileBuffer + 6 >= end) - break; - const IFF::SubChunkHeader head = IFF::LoadSubChunk(mFileBuffer); - - if (mFileBuffer + head.length > end) - throw DeadlyImportError("LWO2: Invalid surface chunk length"); - - uint8_t *const next = mFileBuffer + head.length; - switch (head.type) { - // diffuse color - case AI_LWO_COLR: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, COLR, 12); - surf.mColor.r = GetF4(); - surf.mColor.g = GetF4(); - surf.mColor.b = GetF4(); - break; - } - // diffuse strength ... hopefully - case AI_LWO_DIFF: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, DIFF, 4); - surf.mDiffuseValue = GetF4(); - break; - } - // specular strength ... hopefully - case AI_LWO_SPEC: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SPEC, 4); - surf.mSpecularValue = GetF4(); - break; - } - // transparency - case AI_LWO_TRAN: { - // transparency explicitly disabled? - if (surf.mTransparency == 10e10f) - break; - - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, TRAN, 4); - surf.mTransparency = GetF4(); - break; - } - // additive transparency - case AI_LWO_ADTR: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, ADTR, 4); - surf.mAdditiveTransparency = GetF4(); - break; - } - // wireframe mode - case AI_LWO_LINE: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, LINE, 2); - if (GetU2() & 0x1) - surf.mWireframe = true; - break; - } - // glossiness - case AI_LWO_GLOS: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, GLOS, 4); - surf.mGlossiness = GetF4(); - break; - } - // bump intensity - case AI_LWO_BUMP: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BUMP, 4); - surf.mBumpIntensity = GetF4(); - break; - } - // color highlights - case AI_LWO_CLRH: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, CLRH, 4); - surf.mColorHighlights = GetF4(); - break; - } - // index of refraction - case AI_LWO_RIND: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, RIND, 4); - surf.mIOR = GetF4(); - break; - } - // polygon sidedness - case AI_LWO_SIDE: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SIDE, 2); - surf.bDoubleSided = (3 == GetU2()); - break; - } - // maximum smoothing angle - case AI_LWO_SMAN: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, SMAN, 4); - surf.mMaximumSmoothAngle = std::fabs(GetF4()); - break; - } - // vertex color channel to be applied to the surface - case AI_LWO_VCOL: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, VCOL, 12); - surf.mDiffuseValue *= GetF4(); // strength - ReadVSizedIntLWO2(mFileBuffer); // skip envelope - surf.mVCMapType = GetU4(); // type of the channel - - // name of the channel - GetS0(surf.mVCMap, (unsigned int)(next - mFileBuffer)); - break; - } - // surface bock entry - case AI_LWO_BLOK: { - AI_LWO_VALIDATE_CHUNK_LENGTH(head.length, BLOK, 4); - IFF::SubChunkHeader head2 = IFF::LoadSubChunk(mFileBuffer); - - switch (head2.type) { - case AI_LWO_PROC: - case AI_LWO_GRAD: - case AI_LWO_IMAP: - LoadLWO2TextureBlock(&head2, head.length); - break; - case AI_LWO_SHDR: - LoadLWO2ShaderBlock(&head2, head.length); - break; - - default: - ASSIMP_LOG_WARN("LWO2: Found an unsupported surface BLOK"); - }; - - break; - } - } - mFileBuffer = next; - } -} - -#endif // !! ASSIMP_BUILD_NO_X_IMPORTER -- cgit v1.2.1