diff options
Diffstat (limited to 'src/3rdparty/assimp/code/LWSLoader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/LWSLoader.cpp | 1510 |
1 files changed, 760 insertions, 750 deletions
diff --git a/src/3rdparty/assimp/code/LWSLoader.cpp b/src/3rdparty/assimp/code/LWSLoader.cpp index 20d62569c..a81c15a6e 100644 --- a/src/3rdparty/assimp/code/LWSLoader.cpp +++ b/src/3rdparty/assimp/code/LWSLoader.cpp @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, 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 +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 @@ -25,25 +25,25 @@ conditions are met: 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 +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 +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 +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 +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 LWSLoader.cpp - * @brief Implementation of the LWS importer class + * @brief Implementation of the LWS importer class */ -#include "AssimpPCH.h" + #ifndef ASSIMP_BUILD_NO_LWS_IMPORTER #include "LWSLoader.h" @@ -55,288 +55,298 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SkeletonMeshBuilder.h" #include "ConvertToLHProcess.h" #include "Importer.h" +#include <assimp/DefaultLogger.hpp> +#include <assimp/scene.h> +#include <assimp/IOSystem.hpp> +#include <memory> + using namespace Assimp; static const aiImporterDesc desc = { - "LightWave Scene Importer", - "", - "", - "http://www.newtek.com/lightwave.html=", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "lws mot" + "LightWave Scene Importer", + "", + "", + "http://www.newtek.com/lightwave.html=", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "lws mot" }; // ------------------------------------------------------------------------------------------------ // Recursive parsing of LWS files void LWS::Element::Parse (const char*& buffer) { - for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { - - // begin of a new element with children - bool sub = false; - if (*buffer == '{') { - ++buffer; - SkipSpaces(&buffer); - sub = true; - } - else if (*buffer == '}') - return; - - children.push_back(Element()); - - // copy data line - read token per token - - const char* cur = buffer; - while (!IsSpaceOrNewLine(*buffer)) ++buffer; - children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur)); - SkipSpaces(&buffer); - - if (children.back().tokens[0] == "Plugin") - { - DefaultLogger::get()->debug("LWS: Skipping over plugin-specific data"); - - // strange stuff inside Plugin/Endplugin blocks. Needn't - // follow LWS syntax, so we skip over it - for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { - if (!::strncmp(buffer,"EndPlugin",9)) { - //SkipLine(&buffer); - break; - } - } - continue; - } - - cur = buffer; - while (!IsLineEnd(*buffer)) ++buffer; - children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur)); - - // parse more elements recursively - if (sub) - children.back().Parse(buffer); - } + for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { + + // begin of a new element with children + bool sub = false; + if (*buffer == '{') { + ++buffer; + SkipSpaces(&buffer); + sub = true; + } + else if (*buffer == '}') + return; + + children.push_back(Element()); + + // copy data line - read token per token + + const char* cur = buffer; + while (!IsSpaceOrNewLine(*buffer)) ++buffer; + children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur)); + SkipSpaces(&buffer); + + if (children.back().tokens[0] == "Plugin") + { + DefaultLogger::get()->debug("LWS: Skipping over plugin-specific data"); + + // strange stuff inside Plugin/Endplugin blocks. Needn't + // follow LWS syntax, so we skip over it + for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) { + if (!::strncmp(buffer,"EndPlugin",9)) { + //SkipLine(&buffer); + break; + } + } + continue; + } + + cur = buffer; + while (!IsLineEnd(*buffer)) ++buffer; + children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur)); + + // parse more elements recursively + if (sub) + children.back().Parse(buffer); + } } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer LWSImporter::LWSImporter() -: noSkeletonMesh() + : configSpeedFlag(), + io(), + first(), + last(), + fps(), + noSkeletonMesh() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ -// Destructor, private as well +// Destructor, private as well LWSImporter::~LWSImporter() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. +// Returns whether the class can handle the format of the given file. bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool checkSig) const { - const std::string extension = GetExtension(pFile); - if (extension == "lws" || extension == "mot") - return true; - - // if check for extension is not enough, check for the magic tokens LWSC and LWMO - if (!extension.length() || checkSig) { - uint32_t tokens[2]; - tokens[0] = AI_MAKE_MAGIC("LWSC"); - tokens[1] = AI_MAKE_MAGIC("LWMO"); - return CheckMagicToken(pIOHandler,pFile,tokens,2); - } - return false; + const std::string extension = GetExtension(pFile); + if (extension == "lws" || extension == "mot") + return true; + + // if check for extension is not enough, check for the magic tokens LWSC and LWMO + if (!extension.length() || checkSig) { + uint32_t tokens[2]; + tokens[0] = AI_MAKE_MAGIC("LWSC"); + tokens[1] = AI_MAKE_MAGIC("LWMO"); + return CheckMagicToken(pIOHandler,pFile,tokens,2); + } + return false; } // ------------------------------------------------------------------------------------------------ // Get list of file extensions const aiImporterDesc* LWSImporter::GetInfo () const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration properties void LWSImporter::SetupProperties(const Importer* pImp) { - // AI_CONFIG_FAVOUR_SPEED - configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); + // AI_CONFIG_FAVOUR_SPEED + configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); - // AI_CONFIG_IMPORT_LWS_ANIM_START - first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START, - 150392 /* magic hack */); + // AI_CONFIG_IMPORT_LWS_ANIM_START + first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START, + 150392 /* magic hack */); - // AI_CONFIG_IMPORT_LWS_ANIM_END - last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END, - 150392 /* magic hack */); + // AI_CONFIG_IMPORT_LWS_ANIM_END + last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END, + 150392 /* magic hack */); - if (last < first) { - std::swap(last,first); - } + if (last < first) { + std::swap(last,first); + } - noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; } // ------------------------------------------------------------------------------------------------ // Read an envelope description void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill ) { - if (dad.children.empty()) { - DefaultLogger::get()->error("LWS: Envelope descriptions must not be empty"); - return; - } - - // reserve enough storage - std::list< LWS::Element >::const_iterator it = dad.children.begin();; - fill.keys.reserve(strtoul10(it->tokens[1].c_str())); - - for (++it; it != dad.children.end(); ++it) { - const char* c = (*it).tokens[1].c_str(); - - if ((*it).tokens[0] == "Key") { - fill.keys.push_back(LWO::Key()); - LWO::Key& key = fill.keys.back(); - - float f; - SkipSpaces(&c); - c = fast_atoreal_move<float>(c,key.value); - SkipSpaces(&c); - c = fast_atoreal_move<float>(c,f); - - key.time = f; - - unsigned int span = strtoul10(c,&c), num = 0; - switch (span) { - - case 0: - key.inter = LWO::IT_TCB; - num = 5; - break; - case 1: - case 2: - key.inter = LWO::IT_HERM; - num = 5; - break; - case 3: - key.inter = LWO::IT_LINE; - num = 0; - break; - case 4: - key.inter = LWO::IT_STEP; - num = 0; - break; - case 5: - key.inter = LWO::IT_BEZ2; - num = 4; - break; - default: - DefaultLogger::get()->error("LWS: Unknown span type"); - } - for (unsigned int i = 0; i < num;++i) { - SkipSpaces(&c); - c = fast_atoreal_move<float>(c,key.params[i]); - } - } - else if ((*it).tokens[0] == "Behaviors") { - SkipSpaces(&c); - fill.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); - SkipSpaces(&c); - fill.post = (LWO::PrePostBehaviour) strtoul10(c,&c); - } - } + if (dad.children.empty()) { + DefaultLogger::get()->error("LWS: Envelope descriptions must not be empty"); + return; + } + + // reserve enough storage + std::list< LWS::Element >::const_iterator it = dad.children.begin();; + fill.keys.reserve(strtoul10(it->tokens[1].c_str())); + + for (++it; it != dad.children.end(); ++it) { + const char* c = (*it).tokens[1].c_str(); + + if ((*it).tokens[0] == "Key") { + fill.keys.push_back(LWO::Key()); + LWO::Key& key = fill.keys.back(); + + float f; + SkipSpaces(&c); + c = fast_atoreal_move<float>(c,key.value); + SkipSpaces(&c); + c = fast_atoreal_move<float>(c,f); + + key.time = f; + + unsigned int span = strtoul10(c,&c), num = 0; + switch (span) { + + case 0: + key.inter = LWO::IT_TCB; + num = 5; + break; + case 1: + case 2: + key.inter = LWO::IT_HERM; + num = 5; + break; + case 3: + key.inter = LWO::IT_LINE; + num = 0; + break; + case 4: + key.inter = LWO::IT_STEP; + num = 0; + break; + case 5: + key.inter = LWO::IT_BEZ2; + num = 4; + break; + default: + DefaultLogger::get()->error("LWS: Unknown span type"); + } + for (unsigned int i = 0; i < num;++i) { + SkipSpaces(&c); + c = fast_atoreal_move<float>(c,key.params[i]); + } + } + else if ((*it).tokens[0] == "Behaviors") { + SkipSpaces(&c); + fill.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); + SkipSpaces(&c); + fill.post = (LWO::PrePostBehaviour) strtoul10(c,&c); + } + } } // ------------------------------------------------------------------------------------------------ // Read animation channels in the old LightWave animation format void LWSImporter::ReadEnvelope_Old( - std::list< LWS::Element >::const_iterator& it, - const std::list< LWS::Element >::const_iterator& end, - LWS::NodeDesc& nodes, - unsigned int /*version*/) + std::list< LWS::Element >::const_iterator& it, + const std::list< LWS::Element >::const_iterator& end, + LWS::NodeDesc& nodes, + unsigned int /*version*/) { - unsigned int num,sub_num; - if (++it == end)goto unexpected_end; - - num = strtoul10((*it).tokens[0].c_str()); - for (unsigned int i = 0; i < num; ++i) { - - nodes.channels.push_back(LWO::Envelope()); - LWO::Envelope& envl = nodes.channels.back(); - - envl.index = i; - envl.type = (LWO::EnvelopeType)(i+1); - - if (++it == end)goto unexpected_end; - sub_num = strtoul10((*it).tokens[0].c_str()); - - for (unsigned int n = 0; n < sub_num;++n) { - - if (++it == end)goto unexpected_end; - - // parse value and time, skip the rest for the moment. - LWO::Key key; - const char* c = fast_atoreal_move<float>((*it).tokens[0].c_str(),key.value); - SkipSpaces(&c); - float f; - fast_atoreal_move<float>((*it).tokens[0].c_str(),f); - key.time = f; - - envl.keys.push_back(key); - } - } - return; + unsigned int num,sub_num; + if (++it == end)goto unexpected_end; + + num = strtoul10((*it).tokens[0].c_str()); + for (unsigned int i = 0; i < num; ++i) { + + nodes.channels.push_back(LWO::Envelope()); + LWO::Envelope& envl = nodes.channels.back(); + + envl.index = i; + envl.type = (LWO::EnvelopeType)(i+1); + + if (++it == end)goto unexpected_end; + sub_num = strtoul10((*it).tokens[0].c_str()); + + for (unsigned int n = 0; n < sub_num;++n) { + + if (++it == end)goto unexpected_end; + + // parse value and time, skip the rest for the moment. + LWO::Key key; + const char* c = fast_atoreal_move<float>((*it).tokens[0].c_str(),key.value); + SkipSpaces(&c); + float f; + fast_atoreal_move<float>((*it).tokens[0].c_str(),f); + key.time = f; + + envl.keys.push_back(key); + } + } + return; unexpected_end: - DefaultLogger::get()->error("LWS: Encountered unexpected end of file while parsing object motion"); + DefaultLogger::get()->error("LWS: Encountered unexpected end of file while parsing object motion"); } // ------------------------------------------------------------------------------------------------ -// Setup a nice name for a node +// Setup a nice name for a node void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src) { - const unsigned int combined = src.number | ((unsigned int)src.type) << 28u; + const unsigned int combined = src.number | ((unsigned int)src.type) << 28u; - // the name depends on the type. We break LWS's strange naming convention - // and return human-readable, but still machine-parsable and unique, strings. - if (src.type == LWS::NodeDesc::OBJECT) { + // the name depends on the type. We break LWS's strange naming convention + // and return human-readable, but still machine-parsable and unique, strings. + if (src.type == LWS::NodeDesc::OBJECT) { - if (src.path.length()) { - std::string::size_type s = src.path.find_last_of("\\/"); - if (s == std::string::npos) - s = 0; - else ++s; + if (src.path.length()) { + std::string::size_type s = src.path.find_last_of("\\/"); + if (s == std::string::npos) + s = 0; + else ++s; std::string::size_type t = src.path.substr(s).find_last_of("."); - - nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined); - return; - } - } - nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.name,combined); + + nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined); + return; + } + } + nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)",src.name,combined); } // ------------------------------------------------------------------------------------------------ // Recursively build the scenegraph void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<AttachmentInfo>& attach, - BatchLoader& batch, - aiCamera**& camOut, - aiLight**& lightOut, - std::vector<aiNodeAnim*>& animOut) + BatchLoader& batch, + aiCamera**& camOut, + aiLight**& lightOut, + std::vector<aiNodeAnim*>& animOut) { - // Setup a very cryptic name for the node, we want the user to be happy - SetupNodeName(nd,src); + // Setup a very cryptic name for the node, we want the user to be happy + SetupNodeName(nd,src); aiNode* ndAnim = nd; - // If the node is an object - if (src.type == LWS::NodeDesc::OBJECT) { + // If the node is an object + if (src.type == LWS::NodeDesc::OBJECT) { - // If the object is from an external file, get it - aiScene* obj = NULL; + // If the object is from an external file, get it + aiScene* obj = NULL; if (src.path.length() ) { obj = batch.GetImport(src.id); if (!obj) { @@ -344,18 +354,18 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm } else { if (obj->mRootNode->mNumChildren == 1) { - + //If the pivot is not set for this layer, get it from the external object if (!src.isPivotSet) { src.pivotPos.x = +obj->mRootNode->mTransformation.a4; src.pivotPos.y = +obj->mRootNode->mTransformation.b4; src.pivotPos.z = -obj->mRootNode->mTransformation.c4; //The sign is the RH to LH back conversion } - + //Remove first node from obj (the old pivot), reset transform of second node (the mesh node) aiNode* newRootNode = obj->mRootNode->mChildren[0]; - obj->mRootNode->mChildren[0] = NULL; - delete obj->mRootNode; + obj->mRootNode->mChildren[0] = NULL; + delete obj->mRootNode; obj->mRootNode = newRootNode; obj->mRootNode->mTransformation.a4 = 0.0; @@ -364,11 +374,11 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm } } } - - //Setup the pivot node (also the animation node), the one we received + + //Setup the pivot node (also the animation node), the one we received nd->mName = std::string("Pivot:") + nd->mName.data; - ndAnim = nd; - + ndAnim = nd; + //Add the attachment node to it nd->mNumChildren = 1; nd->mChildren = new aiNode*[1]; @@ -377,547 +387,547 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x; nd->mChildren[0]->mTransformation.b4 = -src.pivotPos.y; nd->mChildren[0]->mTransformation.c4 = -src.pivotPos.z; - SetupNodeName(nd->mChildren[0], src); - - //Update the attachment node - nd = nd->mChildren[0]; - + SetupNodeName(nd->mChildren[0], src); + + //Update the attachment node + nd = nd->mChildren[0]; + //Push attachment, if the object came from an external file if (obj) { attach.push_back(AttachmentInfo(obj,nd)); } } - // If object is a light source - setup a corresponding ai structure - else if (src.type == LWS::NodeDesc::LIGHT) { - aiLight* lit = *lightOut++ = new aiLight(); - - // compute final light color - lit->mColorDiffuse = lit->mColorSpecular = src.lightColor*src.lightIntensity; - - // name to attach light to node -> unique due to LWs indexing system - lit->mName = nd->mName; - - // detemine light type and setup additional members - if (src.lightType == 2) { /* spot light */ - - lit->mType = aiLightSource_SPOT; - lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle ); - lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle ); - - } - else if (src.lightType == 1) { /* directional light source */ - lit->mType = aiLightSource_DIRECTIONAL; - } - else lit->mType = aiLightSource_POINT; - - // fixme: no proper handling of light falloffs yet - if (src.lightFalloffType == 1) - lit->mAttenuationConstant = 1.f; - else if (src.lightFalloffType == 1) - lit->mAttenuationLinear = 1.f; - else - lit->mAttenuationQuadratic = 1.f; - } - - // If object is a camera - setup a corresponding ai structure - else if (src.type == LWS::NodeDesc::CAMERA) { - aiCamera* cam = *camOut++ = new aiCamera(); - - // name to attach cam to node -> unique due to LWs indexing system - cam->mName = nd->mName; - } - - // Get the node transformation from the LWO key - LWO::AnimResolver resolver(src.channels,fps); - resolver.ExtractBindPose(ndAnim->mTransformation); - - // .. and construct animation channels - aiNodeAnim* anim = NULL; - - if (first != last) { - resolver.SetAnimationRange(first,last); - resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO); - if (anim) { - anim->mNodeName = ndAnim->mName; - animOut.push_back(anim); - } - } - - // Add children - if (src.children.size()) { - nd->mChildren = new aiNode*[src.children.size()]; - for (std::list<LWS::NodeDesc*>::iterator it = src.children.begin(); it != src.children.end(); ++it) { - aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode(); - ndd->mParent = nd; - - BuildGraph(ndd,**it,attach,batch,camOut,lightOut,animOut); - } - } + // If object is a light source - setup a corresponding ai structure + else if (src.type == LWS::NodeDesc::LIGHT) { + aiLight* lit = *lightOut++ = new aiLight(); + + // compute final light color + lit->mColorDiffuse = lit->mColorSpecular = src.lightColor*src.lightIntensity; + + // name to attach light to node -> unique due to LWs indexing system + lit->mName = nd->mName; + + // detemine light type and setup additional members + if (src.lightType == 2) { /* spot light */ + + lit->mType = aiLightSource_SPOT; + lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle ); + lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle ); + + } + else if (src.lightType == 1) { /* directional light source */ + lit->mType = aiLightSource_DIRECTIONAL; + } + else lit->mType = aiLightSource_POINT; + + // fixme: no proper handling of light falloffs yet + if (src.lightFalloffType == 1) + lit->mAttenuationConstant = 1.f; + else if (src.lightFalloffType == 1) + lit->mAttenuationLinear = 1.f; + else + lit->mAttenuationQuadratic = 1.f; + } + + // If object is a camera - setup a corresponding ai structure + else if (src.type == LWS::NodeDesc::CAMERA) { + aiCamera* cam = *camOut++ = new aiCamera(); + + // name to attach cam to node -> unique due to LWs indexing system + cam->mName = nd->mName; + } + + // Get the node transformation from the LWO key + LWO::AnimResolver resolver(src.channels,fps); + resolver.ExtractBindPose(ndAnim->mTransformation); + + // .. and construct animation channels + aiNodeAnim* anim = NULL; + + if (first != last) { + resolver.SetAnimationRange(first,last); + resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO); + if (anim) { + anim->mNodeName = ndAnim->mName; + animOut.push_back(anim); + } + } + + // Add children + if (!src.children.empty()) { + nd->mChildren = new aiNode*[src.children.size()]; + for (std::list<LWS::NodeDesc*>::iterator it = src.children.begin(); it != src.children.end(); ++it) { + aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode(); + ndd->mParent = nd; + + BuildGraph(ndd,**it,attach,batch,camOut,lightOut,animOut); + } + } } // ------------------------------------------------------------------------------------------------ // Determine the exact location of a LWO file std::string LWSImporter::FindLWOFile(const std::string& in) { - // insert missing directory seperator if necessary - std::string tmp; - if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/') - { - tmp = in[0] + (":\\" + in.substr(2)); - } - else tmp = in; - - if (io->Exists(tmp)) { - return in; - } - - // file is not accessible for us ... maybe it's packed by - // LightWave's 'Package Scene' command? - - // Relevant for us are the following two directories: - // <folder>\Objects\<hh>\<*>.lwo - // <folder>\Scenes\<hh>\<*>.lws - // where <hh> is optional. - - std::string test = ".." + (io->getOsSeparator() + tmp); - if (io->Exists(test)) { - return test; - } - - test = ".." + (io->getOsSeparator() + test); - if (io->Exists(test)) { - return test; - } - - - // return original path, maybe the IOsystem knows better - return tmp; + // insert missing directory seperator if necessary + std::string tmp; + if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/') + { + tmp = in[0] + (std::string(":\\") + in.substr(2)); + } + else tmp = in; + + if (io->Exists(tmp)) { + return in; + } + + // file is not accessible for us ... maybe it's packed by + // LightWave's 'Package Scene' command? + + // Relevant for us are the following two directories: + // <folder>\Objects\<hh>\<*>.lwo + // <folder>\Scenes\<hh>\<*>.lws + // where <hh> is optional. + + std::string test = std::string("..") + (io->getOsSeparator() + tmp); + if (io->Exists(test)) { + return test; + } + + test = std::string("..") + (io->getOsSeparator() + test); + if (io->Exists(test)) { + return test; + } + + + // return original path, maybe the IOsystem knows better + return tmp; } // ------------------------------------------------------------------------------------------------ // Read file into given scene data structure -void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler) +void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, + IOSystem* pIOHandler) { - io = pIOHandler; - boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); - - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open LWS file " + pFile + "."); - } - - // Allocate storage and copy the contents of the file to a memory buffer - std::vector< char > mBuffer; - TextFileToBuffer(file.get(),mBuffer); - - // Parse the file structure - LWS::Element root; const char* dummy = &mBuffer[0]; - root.Parse(dummy); - - // Construct a Batchimporter to read more files recursively - BatchLoader batch(pIOHandler); -// batch.SetBasePath(pFile); - - // Construct an array to receive the flat output graph - std::list<LWS::NodeDesc> nodes; - - unsigned int cur_light = 0, cur_camera = 0, cur_object = 0; - unsigned int num_light = 0, num_camera = 0, num_object = 0; - - // check magic identifier, 'LWSC' - bool motion_file = false; - std::list< LWS::Element >::const_iterator it = root.children.begin(); - - if ((*it).tokens[0] == "LWMO") - motion_file = true; - - if ((*it).tokens[0] != "LWSC" && !motion_file) - throw DeadlyImportError("LWS: Not a LightWave scene, magic tag LWSC not found"); - - // get file format version and print to log - ++it; - unsigned int version = strtoul10((*it).tokens[0].c_str()); - DefaultLogger::get()->info("LWS file format version is " + (*it).tokens[0]); - first = 0.; - last = 60.; - fps = 25.; /* seems to be a good default frame rate */ - - // Now read all elements in a very straghtforward manner - for (; it != root.children.end(); ++it) { - const char* c = (*it).tokens[1].c_str(); - - // 'FirstFrame': begin of animation slice - if ((*it).tokens[0] == "FirstFrame") { - if (150392. != first /* see SetupProperties() */) - first = strtoul10(c,&c)-1.; /* we're zero-based */ - } - - // 'LastFrame': end of animation slice - else if ((*it).tokens[0] == "LastFrame") { - if (150392. != last /* see SetupProperties() */) - last = strtoul10(c,&c)-1.; /* we're zero-based */ - } - - // 'FramesPerSecond': frames per second - else if ((*it).tokens[0] == "FramesPerSecond") { - fps = strtoul10(c,&c); - } - - // 'LoadObjectLayer': load a layer of a specific LWO file - else if ((*it).tokens[0] == "LoadObjectLayer") { - - // get layer index - const int layer = strtoul10(c,&c); - - // setup the layer to be loaded - BatchLoader::PropertyMap props; - SetGenericProperty(props.ints,AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,layer); - - // add node to list - LWS::NodeDesc d; - d.type = LWS::NodeDesc::OBJECT; - if (version >= 4) { // handle LWSC 4 explicit ID - SkipSpaces(&c); - d.number = strtoul16(c,&c) & AI_LWS_MASK; - } - else d.number = cur_object++; - - // and add the file to the import list - SkipSpaces(&c); - std::string path = FindLWOFile( c ); - d.path = path; - d.id = batch.AddLoadRequest(path,0,&props); - - nodes.push_back(d); - num_object++; - } - // 'LoadObject': load a LWO file into the scenegraph - else if ((*it).tokens[0] == "LoadObject") { - - // add node to list - LWS::NodeDesc d; - d.type = LWS::NodeDesc::OBJECT; - - if (version >= 4) { // handle LWSC 4 explicit ID - d.number = strtoul16(c,&c) & AI_LWS_MASK; - SkipSpaces(&c); - } - else d.number = cur_object++; - std::string path = FindLWOFile( c ); - d.id = batch.AddLoadRequest(path,0,NULL); - - d.path = path; - nodes.push_back(d); - num_object++; - } - // 'AddNullObject': add a dummy node to the hierarchy - else if ((*it).tokens[0] == "AddNullObject") { - - // add node to list - LWS::NodeDesc d; - d.type = LWS::NodeDesc::OBJECT; - if (version >= 4) { // handle LWSC 4 explicit ID - d.number = strtoul16(c,&c) & AI_LWS_MASK; - SkipSpaces(&c); - } - else d.number = cur_object++; + io = pIOHandler; + std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); + + // Check whether we can read from the file + if( file.get() == NULL) { + throw DeadlyImportError( "Failed to open LWS file " + pFile + "."); + } + + // Allocate storage and copy the contents of the file to a memory buffer + std::vector< char > mBuffer; + TextFileToBuffer(file.get(),mBuffer); + + // Parse the file structure + LWS::Element root; const char* dummy = &mBuffer[0]; + root.Parse(dummy); + + // Construct a Batchimporter to read more files recursively + BatchLoader batch(pIOHandler); +// batch.SetBasePath(pFile); + + // Construct an array to receive the flat output graph + std::list<LWS::NodeDesc> nodes; + + unsigned int cur_light = 0, cur_camera = 0, cur_object = 0; + unsigned int num_light = 0, num_camera = 0, num_object = 0; + + // check magic identifier, 'LWSC' + bool motion_file = false; + std::list< LWS::Element >::const_iterator it = root.children.begin(); + + if ((*it).tokens[0] == "LWMO") + motion_file = true; + + if ((*it).tokens[0] != "LWSC" && !motion_file) + throw DeadlyImportError("LWS: Not a LightWave scene, magic tag LWSC not found"); + + // get file format version and print to log + ++it; + unsigned int version = strtoul10((*it).tokens[0].c_str()); + DefaultLogger::get()->info("LWS file format version is " + (*it).tokens[0]); + first = 0.; + last = 60.; + fps = 25.; /* seems to be a good default frame rate */ + + // Now read all elements in a very straghtforward manner + for (; it != root.children.end(); ++it) { + const char* c = (*it).tokens[1].c_str(); + + // 'FirstFrame': begin of animation slice + if ((*it).tokens[0] == "FirstFrame") { + if (150392. != first /* see SetupProperties() */) + first = strtoul10(c,&c)-1.; /* we're zero-based */ + } + + // 'LastFrame': end of animation slice + else if ((*it).tokens[0] == "LastFrame") { + if (150392. != last /* see SetupProperties() */) + last = strtoul10(c,&c)-1.; /* we're zero-based */ + } + + // 'FramesPerSecond': frames per second + else if ((*it).tokens[0] == "FramesPerSecond") { + fps = strtoul10(c,&c); + } + + // 'LoadObjectLayer': load a layer of a specific LWO file + else if ((*it).tokens[0] == "LoadObjectLayer") { + + // get layer index + const int layer = strtoul10(c,&c); + + // setup the layer to be loaded + BatchLoader::PropertyMap props; + SetGenericProperty(props.ints,AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,layer); + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + if (version >= 4) { // handle LWSC 4 explicit ID + SkipSpaces(&c); + d.number = strtoul16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_object++; + + // and add the file to the import list + SkipSpaces(&c); + std::string path = FindLWOFile( c ); + d.path = path; + d.id = batch.AddLoadRequest(path,0,&props); + + nodes.push_back(d); + num_object++; + } + // 'LoadObject': load a LWO file into the scenegraph + else if ((*it).tokens[0] == "LoadObject") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtoul16(c,&c) & AI_LWS_MASK; + SkipSpaces(&c); + } + else d.number = cur_object++; + std::string path = FindLWOFile( c ); + d.id = batch.AddLoadRequest(path,0,NULL); + + d.path = path; + nodes.push_back(d); + num_object++; + } + // 'AddNullObject': add a dummy node to the hierarchy + else if ((*it).tokens[0] == "AddNullObject") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtoul16(c,&c) & AI_LWS_MASK; + SkipSpaces(&c); + } + else d.number = cur_object++; d.name = c; - nodes.push_back(d); - - num_object++; - } - // 'NumChannels': Number of envelope channels assigned to last layer - else if ((*it).tokens[0] == "NumChannels") { - // ignore for now - } - // 'Channel': preceedes any envelope description - else if ((*it).tokens[0] == "Channel") { - if (nodes.empty()) { - if (motion_file) { - - // LightWave motion file. Add dummy node - LWS::NodeDesc d; - d.type = LWS::NodeDesc::OBJECT; - d.name = c; - d.number = cur_object++; - nodes.push_back(d); - } - else DefaultLogger::get()->error("LWS: Unexpected keyword: \'Channel\'"); - } - - // important: index of channel - nodes.back().channels.push_back(LWO::Envelope()); - LWO::Envelope& env = nodes.back().channels.back(); - - env.index = strtoul10(c); - - // currently we can just interpret the standard channels 0...9 - // (hack) assume that index-i yields the binary channel type from LWO - env.type = (LWO::EnvelopeType)(env.index+1); - - } - // 'Envelope': a single animation channel - else if ((*it).tokens[0] == "Envelope") { - if (nodes.empty() || nodes.back().channels.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'Envelope\'"); - else { - ReadEnvelope((*it),nodes.back().channels.back()); - } - } - // 'ObjectMotion': animation information for older lightwave formats - else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" || - (*it).tokens[0] == "CameraMotion" || - (*it).tokens[0] == "LightMotion")) { - - if (nodes.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'"); - else { - ReadEnvelope_Old(it,root.children.end(),nodes.back(),version); - } - } - // 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2 - else if (version == 2 && (*it).tokens[0] == "Pre/PostBehavior") { - if (nodes.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'Pre/PostBehavior'"); - else { - for (std::list<LWO::Envelope>::iterator it = nodes.back().channels.begin(); it != nodes.back().channels.end(); ++it) { - // two ints per envelope - LWO::Envelope& env = *it; - env.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c); - env.post = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c); - } - } - } - // 'ParentItem': specifies the parent of the current element - else if ((*it).tokens[0] == "ParentItem") { - if (nodes.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentItem\'"); - - else nodes.back().parent = strtoul16(c,&c); - } - // 'ParentObject': deprecated one for older formats - else if (version < 3 && (*it).tokens[0] == "ParentObject") { - if (nodes.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentObject\'"); - - else { - nodes.back().parent = strtoul10(c,&c) | (1u << 28u); - } - } - // 'AddCamera': add a camera to the scenegraph - else if ((*it).tokens[0] == "AddCamera") { - - // add node to list - LWS::NodeDesc d; - d.type = LWS::NodeDesc::CAMERA; - - if (version >= 4) { // handle LWSC 4 explicit ID - d.number = strtoul16(c,&c) & AI_LWS_MASK; - } - else d.number = cur_camera++; - nodes.push_back(d); - - num_camera++; - } - // 'CameraName': set name of currently active camera - else if ((*it).tokens[0] == "CameraName") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'CameraName\'"); - - else nodes.back().name = c; - } - // 'AddLight': add a light to the scenegraph - else if ((*it).tokens[0] == "AddLight") { - - // add node to list - LWS::NodeDesc d; - d.type = LWS::NodeDesc::LIGHT; - - if (version >= 4) { // handle LWSC 4 explicit ID - d.number = strtoul16(c,&c) & AI_LWS_MASK; - } - else d.number = cur_light++; - nodes.push_back(d); - - num_light++; - } - // 'LightName': set name of currently active light - else if ((*it).tokens[0] == "LightName") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightName\'"); - - else nodes.back().name = c; - } - // 'LightIntensity': set intensity of currently active light - else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity" ) { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightIntensity\'"); - - else fast_atoreal_move<float>(c, nodes.back().lightIntensity ); - - } - // 'LightType': set type of currently active light - else if ((*it).tokens[0] == "LightType") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightType\'"); - - else nodes.back().lightType = strtoul10(c); - - } - // 'LightFalloffType': set falloff type of currently active light - else if ((*it).tokens[0] == "LightFalloffType") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightFalloffType\'"); - - else nodes.back().lightFalloffType = strtoul10(c); - - } - // 'LightConeAngle': set cone angle of currently active light - else if ((*it).tokens[0] == "LightConeAngle") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightConeAngle\'"); - - else nodes.back().lightConeAngle = fast_atof(c); - - } - // 'LightEdgeAngle': set area where we're smoothing from min to max intensity - else if ((*it).tokens[0] == "LightEdgeAngle") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightEdgeAngle\'"); - - else nodes.back().lightEdgeAngle = fast_atof(c); - - } - // 'LightColor': set color of currently active light - else if ((*it).tokens[0] == "LightColor") { - if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightColor\'"); - - else { - c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.r ); - SkipSpaces(&c); - c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.g ); - SkipSpaces(&c); - c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.b ); - } - } - - // 'PivotPosition': position of local transformation origin - else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") { - if (nodes.empty()) - DefaultLogger::get()->error("LWS: Unexpected keyword: \'PivotPosition\'"); - else { - c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.x ); - SkipSpaces(&c); - c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.y ); - SkipSpaces(&c); - c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.z ); + nodes.push_back(d); + + num_object++; + } + // 'NumChannels': Number of envelope channels assigned to last layer + else if ((*it).tokens[0] == "NumChannels") { + // ignore for now + } + // 'Channel': preceedes any envelope description + else if ((*it).tokens[0] == "Channel") { + if (nodes.empty()) { + if (motion_file) { + + // LightWave motion file. Add dummy node + LWS::NodeDesc d; + d.type = LWS::NodeDesc::OBJECT; + d.name = c; + d.number = cur_object++; + nodes.push_back(d); + } + else DefaultLogger::get()->error("LWS: Unexpected keyword: \'Channel\'"); + } + + // important: index of channel + nodes.back().channels.push_back(LWO::Envelope()); + LWO::Envelope& env = nodes.back().channels.back(); + + env.index = strtoul10(c); + + // currently we can just interpret the standard channels 0...9 + // (hack) assume that index-i yields the binary channel type from LWO + env.type = (LWO::EnvelopeType)(env.index+1); + + } + // 'Envelope': a single animation channel + else if ((*it).tokens[0] == "Envelope") { + if (nodes.empty() || nodes.back().channels.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'Envelope\'"); + else { + ReadEnvelope((*it),nodes.back().channels.back()); + } + } + // 'ObjectMotion': animation information for older lightwave formats + else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" || + (*it).tokens[0] == "CameraMotion" || + (*it).tokens[0] == "LightMotion")) { + + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'"); + else { + ReadEnvelope_Old(it,root.children.end(),nodes.back(),version); + } + } + // 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2 + else if (version == 2 && (*it).tokens[0] == "Pre/PostBehavior") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'Pre/PostBehavior'"); + else { + for (std::list<LWO::Envelope>::iterator it = nodes.back().channels.begin(); it != nodes.back().channels.end(); ++it) { + // two ints per envelope + LWO::Envelope& env = *it; + env.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c); + env.post = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c); + } + } + } + // 'ParentItem': specifies the parent of the current element + else if ((*it).tokens[0] == "ParentItem") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentItem\'"); + + else nodes.back().parent = strtoul16(c,&c); + } + // 'ParentObject': deprecated one for older formats + else if (version < 3 && (*it).tokens[0] == "ParentObject") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentObject\'"); + + else { + nodes.back().parent = strtoul10(c,&c) | (1u << 28u); + } + } + // 'AddCamera': add a camera to the scenegraph + else if ((*it).tokens[0] == "AddCamera") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::CAMERA; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtoul16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_camera++; + nodes.push_back(d); + + num_camera++; + } + // 'CameraName': set name of currently active camera + else if ((*it).tokens[0] == "CameraName") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'CameraName\'"); + + else nodes.back().name = c; + } + // 'AddLight': add a light to the scenegraph + else if ((*it).tokens[0] == "AddLight") { + + // add node to list + LWS::NodeDesc d; + d.type = LWS::NodeDesc::LIGHT; + + if (version >= 4) { // handle LWSC 4 explicit ID + d.number = strtoul16(c,&c) & AI_LWS_MASK; + } + else d.number = cur_light++; + nodes.push_back(d); + + num_light++; + } + // 'LightName': set name of currently active light + else if ((*it).tokens[0] == "LightName") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightName\'"); + + else nodes.back().name = c; + } + // 'LightIntensity': set intensity of currently active light + else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity" ) { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightIntensity\'"); + + else fast_atoreal_move<float>(c, nodes.back().lightIntensity ); + + } + // 'LightType': set type of currently active light + else if ((*it).tokens[0] == "LightType") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightType\'"); + + else nodes.back().lightType = strtoul10(c); + + } + // 'LightFalloffType': set falloff type of currently active light + else if ((*it).tokens[0] == "LightFalloffType") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightFalloffType\'"); + + else nodes.back().lightFalloffType = strtoul10(c); + + } + // 'LightConeAngle': set cone angle of currently active light + else if ((*it).tokens[0] == "LightConeAngle") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightConeAngle\'"); + + else nodes.back().lightConeAngle = fast_atof(c); + + } + // 'LightEdgeAngle': set area where we're smoothing from min to max intensity + else if ((*it).tokens[0] == "LightEdgeAngle") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightEdgeAngle\'"); + + else nodes.back().lightEdgeAngle = fast_atof(c); + + } + // 'LightColor': set color of currently active light + else if ((*it).tokens[0] == "LightColor") { + if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightColor\'"); + + else { + c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.r ); + SkipSpaces(&c); + c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.g ); + SkipSpaces(&c); + c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.b ); + } + } + + // 'PivotPosition': position of local transformation origin + else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") { + if (nodes.empty()) + DefaultLogger::get()->error("LWS: Unexpected keyword: \'PivotPosition\'"); + else { + c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.x ); + SkipSpaces(&c); + c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.y ); + SkipSpaces(&c); + c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.z ); // Mark pivotPos as set nodes.back().isPivotSet = true; - } - } - } - - // resolve parenting - for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { - - // check whether there is another node which calls us a parent - for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) { - if (dit != it && *it == (*dit).parent) { - if ((*dit).parent_resolved) { - // fixme: it's still possible to produce an overflow due to cross references .. - DefaultLogger::get()->error("LWS: Found cross reference in scenegraph"); - continue; - } - - (*it).children.push_back(&*dit); - (*dit).parent_resolved = &*it; - } - } - } - - // find out how many nodes have no parent yet - unsigned int no_parent = 0; - for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { - if (!(*it).parent_resolved) - ++ no_parent; - } - if (!no_parent) - throw DeadlyImportError("LWS: Unable to find scene root node"); - - - // Load all subsequent files - batch.LoadAll(); - - // and build the final output graph by attaching the loaded external - // files to ourselves. first build a master graph - aiScene* master = new aiScene(); - aiNode* nd = master->mRootNode = new aiNode(); - - // allocate storage for cameras&lights - if (num_camera) { - master->mCameras = new aiCamera*[master->mNumCameras = num_camera]; - } - aiCamera** cams = master->mCameras; - if (num_light) { - master->mLights = new aiLight*[master->mNumLights = num_light]; - } - aiLight** lights = master->mLights; - - std::vector<AttachmentInfo> attach; - std::vector<aiNodeAnim*> anims; - - nd->mName.Set("<LWSRoot>"); - nd->mChildren = new aiNode*[no_parent]; - for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { - if (!(*it).parent_resolved) { - aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode(); - ro->mParent = nd; - - // ... and build the scene graph. If we encounter object nodes, - // add then to our attachment table. - BuildGraph(ro,*it, attach, batch, cams, lights, anims); - } - } - - // create a master animation channel for us - if (anims.size()) { - master->mAnimations = new aiAnimation*[master->mNumAnimations = 1]; - aiAnimation* anim = master->mAnimations[0] = new aiAnimation(); - anim->mName.Set("LWSMasterAnim"); - - // LWS uses seconds as time units, but we convert to frames - anim->mTicksPerSecond = fps; - anim->mDuration = last-(first-1); /* fixme ... zero or one-based?*/ - - anim->mChannels = new aiNodeAnim*[anim->mNumChannels = anims.size()]; - std::copy(anims.begin(),anims.end(),anim->mChannels); - } - - // convert the master scene to RH - MakeLeftHandedProcess monster_cheat; - monster_cheat.Execute(master); - - // .. ccw - FlipWindingOrderProcess flipper; - flipper.Execute(master); - - // OK ... finally build the output graph - SceneCombiner::MergeScenes(&pScene,master,attach, - AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( - AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0)); - - // Check flags - if (!pScene->mNumMeshes || !pScene->mNumMaterials) { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - - if (pScene->mNumAnimations && !noSkeletonMesh) { - // construct skeleton mesh - SkeletonMeshBuilder builder(pScene); - } - } + } + } + } + + // resolve parenting + for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { + + // check whether there is another node which calls us a parent + for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) { + if (dit != it && *it == (*dit).parent) { + if ((*dit).parent_resolved) { + // fixme: it's still possible to produce an overflow due to cross references .. + DefaultLogger::get()->error("LWS: Found cross reference in scenegraph"); + continue; + } + + (*it).children.push_back(&*dit); + (*dit).parent_resolved = &*it; + } + } + } + + // find out how many nodes have no parent yet + unsigned int no_parent = 0; + for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { + if (!(*it).parent_resolved) + ++ no_parent; + } + if (!no_parent) + throw DeadlyImportError("LWS: Unable to find scene root node"); + + + // Load all subsequent files + batch.LoadAll(); + + // and build the final output graph by attaching the loaded external + // files to ourselves. first build a master graph + aiScene* master = new aiScene(); + aiNode* nd = master->mRootNode = new aiNode(); + + // allocate storage for cameras&lights + if (num_camera) { + master->mCameras = new aiCamera*[master->mNumCameras = num_camera]; + } + aiCamera** cams = master->mCameras; + if (num_light) { + master->mLights = new aiLight*[master->mNumLights = num_light]; + } + aiLight** lights = master->mLights; + + std::vector<AttachmentInfo> attach; + std::vector<aiNodeAnim*> anims; + + nd->mName.Set("<LWSRoot>"); + nd->mChildren = new aiNode*[no_parent]; + for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) { + if (!(*it).parent_resolved) { + aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode(); + ro->mParent = nd; + + // ... and build the scene graph. If we encounter object nodes, + // add then to our attachment table. + BuildGraph(ro,*it, attach, batch, cams, lights, anims); + } + } + + // create a master animation channel for us + if (anims.size()) { + master->mAnimations = new aiAnimation*[master->mNumAnimations = 1]; + aiAnimation* anim = master->mAnimations[0] = new aiAnimation(); + anim->mName.Set("LWSMasterAnim"); + + // LWS uses seconds as time units, but we convert to frames + anim->mTicksPerSecond = fps; + anim->mDuration = last-(first-1); /* fixme ... zero or one-based?*/ + + anim->mChannels = new aiNodeAnim*[anim->mNumChannels = anims.size()]; + std::copy(anims.begin(),anims.end(),anim->mChannels); + } + + // convert the master scene to RH + MakeLeftHandedProcess monster_cheat; + monster_cheat.Execute(master); + + // .. ccw + FlipWindingOrderProcess flipper; + flipper.Execute(master); + + // OK ... finally build the output graph + SceneCombiner::MergeScenes(&pScene,master,attach, + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( + AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0)); + + // Check flags + if (!pScene->mNumMeshes || !pScene->mNumMaterials) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + + if (pScene->mNumAnimations && !noSkeletonMesh) { + // construct skeleton mesh + SkeletonMeshBuilder builder(pScene); + } + } } |