Model loading and texturing
This commit is contained in:
604
thirdparty/assimp/code/LWO/LWOAnimation.cpp
vendored
Normal file
604
thirdparty/assimp/code/LWO/LWOAnimation.cpp
vendored
Normal file
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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
|
||||
* componentwise-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 <functional>
|
||||
|
||||
// internal headers
|
||||
#include "LWOFileData.h"
|
||||
#include <assimp/anim.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::LWO;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct an animation resolver from a given list of envelopes
|
||||
AnimResolver::AnimResolver(std::list<Envelope>& _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 = NULL;
|
||||
rotat_x = rotat_y = rotat_z = NULL;
|
||||
scale_x = scale_y = scale_z = NULL;
|
||||
|
||||
first = last = 150392.;
|
||||
|
||||
// find transformation envelopes
|
||||
for (std::list<LWO::Envelope>::iterator it = envelopes.begin(); it != envelopes.end(); ++it) {
|
||||
|
||||
(*it).old_first = 0;
|
||||
(*it).old_last = (*it).keys.size()-1;
|
||||
|
||||
if ((*it).keys.empty()) 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<LWO::Key>::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<LWO::Envelope>::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 behaviours.
|
||||
void AnimResolver::UpdateAnimRangeSetup()
|
||||
{
|
||||
// XXX doesn't work yet (hangs if more than one envelope channels needs to be interpolated)
|
||||
|
||||
for (std::list<LWO::Envelope>::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 behaviour
|
||||
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<LWO::Key>::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);
|
||||
|
||||
if ((*it).pre == LWO::PrePostBehaviour_Oscillate && (reverse = !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 behaviour
|
||||
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<LWO::Key>::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<LWO::Key>::const_iterator beg,
|
||||
std::vector<LWO::Key>::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<aiVectorKey>& /*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<aiVectorKey>& 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<aiVectorKey>& 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<aiVectorKey>::iterator it = out.begin(); it != out.end(); ++it)
|
||||
(*it).mTime -= first;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Extract animation channel
|
||||
void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0*/)
|
||||
{
|
||||
*out = NULL;
|
||||
|
||||
|
||||
//FIXME: crashes if more than one component is animated at different timings, to be resolved.
|
||||
|
||||
// If we have no envelopes, return NULL
|
||||
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<aiVectorKey> keys;
|
||||
GetKeys(keys,trans_x,trans_y,trans_z,flags);
|
||||
|
||||
anim->mPositionKeys = new aiVectorKey[ anim->mNumPositionKeys = static_cast<unsigned int>(keys.size()) ];
|
||||
std::copy(keys.begin(),keys.end(),anim->mPositionKeys);
|
||||
}
|
||||
|
||||
// copy rotation keys
|
||||
if (rotat) {
|
||||
std::vector<aiVectorKey> keys;
|
||||
GetKeys(keys,rotat_x,rotat_y,rotat_z,flags);
|
||||
|
||||
anim->mRotationKeys = new aiQuatKey[ anim->mNumRotationKeys = static_cast<unsigned int>(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<aiVectorKey> keys;
|
||||
GetKeys(keys,scale_x,scale_y,scale_z,flags);
|
||||
|
||||
anim->mScalingKeys = new aiVectorKey[ anim->mNumScalingKeys = static_cast<unsigned int>(keys.size()) ];
|
||||
std::copy(keys.begin(),keys.end(),anim->mScalingKeys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // no lwo or no lws
|
||||
346
thirdparty/assimp/code/LWO/LWOAnimation.h
vendored
Normal file
346
thirdparty/assimp/code/LWO/LWOAnimation.h
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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 <vector>
|
||||
#include <list>
|
||||
|
||||
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<Key> 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<Envelope>& 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 NULL 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 NULL
|
||||
*/
|
||||
void GetKeys(std::vector<aiVectorKey>& 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<LWO::Key>::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<LWO::Key>::const_iterator beg,
|
||||
std::vector<LWO::Key>::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<aiVectorKey>& 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<aiVectorKey>& 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<Envelope>& 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<LWO::Key>::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
|
||||
428
thirdparty/assimp/code/LWO/LWOBLoader.cpp
vendored
Normal file
428
thirdparty/assimp/code/LWO/LWOBLoader.cpp
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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_F("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 = NULL;
|
||||
|
||||
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
|
||||
703
thirdparty/assimp/code/LWO/LWOFileData.h
vendored
Normal file
703
thirdparty/assimp/code/LWO/LWOFileData.h
vendored
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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 <vector>
|
||||
#include <list>
|
||||
|
||||
// public ASSIMP headers
|
||||
#include <assimp/mesh.h>
|
||||
|
||||
// internal headers
|
||||
#include "Common/IFF.h"
|
||||
#include "LWO/LWOAnimation.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<float> rawData;
|
||||
std::vector<bool> 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 < Texture > TextureList;
|
||||
typedef std::list < Shader > 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 < aiVector3D > PointList;
|
||||
typedef std::vector < LWO::Face > FaceList;
|
||||
typedef std::vector < LWO::Surface > SurfaceList;
|
||||
typedef std::vector < std::string > TagList;
|
||||
typedef std::vector < unsigned int > TagMappingTable;
|
||||
typedef std::vector < unsigned int > ReferrerList;
|
||||
typedef std::vector < WeightChannel > WeightChannelList;
|
||||
typedef std::vector < VColorChannel > VColorChannelList;
|
||||
typedef std::vector < UVChannel > UVChannelList;
|
||||
typedef std::vector < Clip > ClipList;
|
||||
typedef std::vector < Envelope > EnvelopeList;
|
||||
typedef std::vector < unsigned int > 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<LWO::Layer> LayerList;
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif // !! AI_LWO_FILEDATA_INCLUDED
|
||||
|
||||
1490
thirdparty/assimp/code/LWO/LWOLoader.cpp
vendored
Normal file
1490
thirdparty/assimp/code/LWO/LWOLoader.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
490
thirdparty/assimp/code/LWO/LWOLoader.h
vendored
Normal file
490
thirdparty/assimp/code/LWO/LWOLoader.h
vendored
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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. */
|
||||
#ifndef AI_LWOLOADER_H_INCLUDED
|
||||
#define AI_LWOLOADER_H_INCLUDED
|
||||
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include "LWOFileData.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
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();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** 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);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get list of supported extensions
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
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<uint16_t,aiNode*>& 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 NULL.
|
||||
*/
|
||||
void AddChildren(aiNode* node, uint16_t parent,
|
||||
std::vector<aiNode*>& 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<unsigned int>& 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* pScene;
|
||||
|
||||
/** 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
|
||||
898
thirdparty/assimp/code/LWO/LWOMaterial.cpp
vendored
Normal file
898
thirdparty/assimp/code/LWO/LWOMaterial.cpp
vendored
Normal file
@@ -0,0 +1,898 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, 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 <assimp/ByteSwapper.h>
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <class T>
|
||||
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(NULL != 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;
|
||||
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>((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_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<float>(&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>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
|
||||
|
||||
// setup the mapping mode
|
||||
int mapping_ = static_cast<int>(mapping);
|
||||
pcMat->AddProperty<int>(&mapping_, 1, AI_MATKEY_MAPPING(type, cur));
|
||||
|
||||
// add the u-wrapping
|
||||
temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
|
||||
pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_MAPPINGMODE_U(type,cur));
|
||||
|
||||
// add the v-wrapping
|
||||
temp = (unsigned int)GetMapMode(texture.wrapModeHeight);
|
||||
pcMat->AddProperty<int>((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<aiColor3D>(&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_F("LWO2: Unknown surface shader: ", shader.functionName);
|
||||
}
|
||||
}
|
||||
if (surf.mMaximumSmoothAngle <= 0.0)
|
||||
m = aiShadingMode_Flat;
|
||||
int m_ = static_cast<int>(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<aiColor3D>(&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 = NULL;
|
||||
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(), end = mSurfaces->end()-1; it != end; ++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
|
||||
Reference in New Issue
Block a user