/** * This source file is part of OgreColladaPlugin * an addon for OGRE (Object-oriented Graphics Rendering Engine) * For the latest info, see http://www.ogre3d.org/ * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA, or go to * http://www.gnu.org/copyleft/lesser.txt. * * @author Philipp Hartl * @see README */ #include "OgreColladaScene.h" #include "OgreColladaDocument.h" #include "OgreColladaGeometry.h" #include "OgreColladaLibrary.h" #include "OgreColladaSyntax.h" #include "OgreColladaUtils.h" #include "OgreStringVector.h" #include "OgreAxisAlignedBox.h" #include "OgreStringConverter.h" #include "OgreSceneManager.h" namespace Ogre { //------------------------------------------------------------------------- ColladaBoundingBox::ColladaBoundingBox(ColladaSceneNode *p) : ColladaNodeElement(p) { mMin = Vector3::ZERO; mMax = Vector3::ZERO; } //------------------------------------------------------------------------- ColladaBoundingBox::ColladaBoundingBox(const Vector3 &min, const Vector3 &max) : ColladaNodeElement(NULL), mMin(min), mMax(max) { } //------------------------------------------------------------------------- ColladaBoundingBox::~ColladaBoundingBox(void) { } //------------------------------------------------------------------------- void ColladaBoundingBox::doImport(xmlNode *node) { if (node == NULL) return; for (xmlNode *c = node->children; c != NULL; c = c->next) { if (c->type != XML_ELEMENT_NODE) continue; String tagname = (const char *)c->name; // if (tagname == CS_ELM_MIN) { // fill up minimum vector mMin = StringConverter::parseVector3(ColladaUtils::getContentDirect(c)); } // else if (tagname == CS_ELM_MAX) { // fill up maximum vector mMax = StringConverter::parseVector3(ColladaUtils::getContentDirect(c)); } // unknown or unsupported else { LogManager::getSingleton().logMessage("ColladaBoundingBox::doImport - unknown child: " + tagname); } } } //------------------------------------------------------------------------- AxisAlignedBox ColladaBoundingBox::getAABB(void) const { return AxisAlignedBox(mMin, mMax); } //------------------------------------------------------------------------- float ColladaBoundingBox::getRadius(void) const { Vector3 dist = mMax - (mMax + mMin) * 0.5; return dist.length(); } //------------------------------------------------------------------------- String ColladaBoundingBox::toString(void) const { return "min: " + StringConverter::toString(mMin) + " max: " + StringConverter::toString(mMax); } //------------------------------------------------------------------------- // ColladaScene //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaSceneNode::ColladaSceneNode(ColladaDocument *doc, xmlNode *node) : ColladaEntity(doc, node) { mType = NODE; mBB = NULL; mParent = NULL; mEntity = NULL; } //------------------------------------------------------------------------- ColladaSceneNode::~ColladaSceneNode(void) { for (ColladaSceneNodePtrVector::iterator it = mChilds.begin(); it != mChilds.end(); ++it) { OGRE_DELETE(*it); } mChilds.clear(); mParent = NULL; mEntity = NULL; // the entities will be cleared by the library container for (ColladaTransformPtrVector::iterator jt = mTransforms.begin(); jt != mTransforms.end(); ++jt) { OGRE_DELETE(*jt); } mTransforms.clear(); OGRE_DELETE(mBB); } //------------------------------------------------------------------------- void ColladaSceneNode::attachEntityToOgreSceneNode(SceneNode *ogrenode) const { if (mEntity == NULL || ogrenode == NULL) return; if (mEntity->getEntityType() == GEOMETRY || mEntity->getEntityType() == LIGHT || mEntity->getEntityType() == CAMERA) { // the geometry need some special data if (mEntity->getEntityType() == GEOMETRY) { ColladaGeometry *geo = static_cast(mEntity); geo->setEntityName(mId); // a unique name for the ogre entity, should not be NULL! // geo->setBoundingBox(mBB); // a bounding box, can be NULL } // create an ogre entity MovableObject *mo = mEntity->getOgreInstance(); if (mo != NULL) ogrenode->attachObject(mo); } } //------------------------------------------------------------------------- void ColladaSceneNode::attachTransformsToOgreSceneNode(SceneNode *ogrenode) const { if (ogrenode == NULL || mTransforms.empty()) return; for (ColladaTransformPtrVector::const_iterator it = mTransforms.begin(); it != mTransforms.end(); ++it) { if ((*it)->getType() == ColladaTransform::ROTATE) { // rotation has local affects ColladaTRotate *r = static_cast(*it); Quaternion rot(Degree(r->getAngle()), r->getAxis()); mDoc->correctAxis(rot); ogrenode->rotate(rot); } else if ((*it)->getType() == ColladaTransform::SCALE) { ogrenode->scale(static_cast(*it)->getScale()); } else if ((*it)->getType() == ColladaTransform::TRANSLATE) { // translation is relative to parent ogrenode->translate(static_cast(*it)->getTranslate()); } } // correct transforms for ogre axis Vector3 pos = ogrenode->getPosition(); mDoc->correctAxis(pos); ogrenode->setPosition(pos); } //------------------------------------------------------------------------- void ColladaSceneNode::createOgreInstance(SceneNode *ogrenode) const { if (ogrenode == NULL) ogrenode = mDoc->getSceneManager()->getRootSceneNode(); if (mType == NODE) { // transforms attachTransformsToOgreSceneNode(ogrenode); // boundingbox // entity attachEntityToOgreSceneNode(ogrenode); } for (ColladaSceneNodePtrVector::const_iterator it = mChilds.begin(); it != mChilds.end(); ++it) { // the new child will be automatically attached to the scene graph (*it)->createOgreInstance(ogrenode->createChildSceneNode((*it)->mId)); } } //------------------------------------------------------------------------- bool ColladaSceneNode::doImport(void) { if (mLoaded) return mStatus; else mLoaded = true; // get unique identifier of scene initialise(); // if the xmlNode is a there could be a type attribute [JOINT or NODE] (last is default) String type = ColladaUtils::getProperty(mNode, CS_ATR_TYPE); if (!type.empty()) { if (type == CS_VAL_NODE_TYPE_JOINT) mType = JOINT; } // walk through child elements, the order is important for (xmlNode *child = mNode->children; child != NULL; child = child->next) { // we are interested on element nodes only if (child->type != XML_ELEMENT_NODE) continue; String tagname = (const char *)child->name; // look for if (tagname == CS_ELM_EXTRA) { importExtra(child); } // look for else if (tagname == CS_ELM_BOUNDINGBOX) { mBB = new ColladaBoundingBox(this); mBB->doImport(child); } // look for (build up subtree) else if (tagname == CS_ELM_NODE) { ColladaSceneNode *snode = new ColladaSceneNode(mDoc, child); if (!snode->doImport()) return false; // each node should be unique snode->mParent = this; mChilds.push_back(snode); } // look for and link entity else if (tagname == CS_ELM_INSTANCE) { importInstance(child); } // look for transformations , ... else if (tagname == CS_ELM_LOOKAT || tagname == CS_ELM_MATRIX || tagname == CS_ELM_PERSPECTIVE || tagname == CS_ELM_ROTATE || tagname == CS_ELM_SCALE || tagname == CS_ELM_SKEW || tagname == CS_ELM_TRANSLATE) { ColladaTransform *t; if (tagname == CS_ELM_LOOKAT) t = new ColladaTLookAt(this); else if (tagname == CS_ELM_MATRIX) t = new ColladaTMatrix(this); else if (tagname == CS_ELM_PERSPECTIVE) t = new ColladaTPerspective(this); else if (tagname == CS_ELM_ROTATE) t = new ColladaTRotate(this); else if (tagname == CS_ELM_SCALE) t = new ColladaTScale(this); else if (tagname == CS_ELM_SKEW) t = new ColladaTSkew(this); else if (tagname == CS_ELM_TRANSLATE) t = new ColladaTTranslate(this); else t = NULL; if (t != NULL) { t->doImport(child); mTransforms.push_back(t); } } else { LogManager::getSingleton().logMessage("ColladaSceneNode::doImport - unknown child: " + tagname + " of " + mId); } } mStatus = true; return mStatus; } //------------------------------------------------------------------------- ColladaSceneNode *ColladaSceneNode::getNode(const String &id) { if (this->mId == id) return this; ColladaSceneNode *tmp = NULL; for (ColladaSceneNodePtrVector::const_iterator it = mChilds.begin(); it != mChilds.end(); ++it) { tmp = (*it)->getNode(id); if (tmp != NULL) break; } return tmp; } //------------------------------------------------------------------------- void ColladaSceneNode::importExtra(xmlNode *node) { // not yet implemented // scene extra information } //------------------------------------------------------------------------- void ColladaSceneNode::importInstance(xmlNode *node) { String url = ColladaUtils::getProperty(node, CS_ATR_URL); if (url.empty()) { LogManager::getSingleton().logMessage("ColladaSceneNode::importInstance - no instance url is given!"); return; } // local reference if (url.find("#") == 0) { // we do not need the # sign url.erase(0,1); // we do not know where the instance belongs to, so let library to find out mEntity = mDoc->getLibrary()->importInstance(url); if (mEntity == NULL) { LogManager::getSingleton().logMessage("ColladaSceneNode::importInstance - creating instance of " + url + " failed"); } } // external reference else { // not yet implemented !! LogManager::getSingleton().logMessage("ColladaSceneNode::importInstance - external references are currently not implemented!"); } } //------------------------------------------------------------------------- // ColladaTransform(s) //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTLookAt::ColladaTLookAt(ColladaSceneNode *p) : ColladaTransform(p) { mMatrix = Matrix3::IDENTITY; } //------------------------------------------------------------------------- ColladaTLookAt::~ColladaTLookAt(void) { } //------------------------------------------------------------------------- void ColladaTLookAt::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; StringVector lines = StringUtil::split(content,"\r\n"); if (lines.size() != 3) return; uint i = 0; for (StringVector::iterator it = lines.begin(); it != lines.end(); ++it) { uint j = 0; StringUtil::trim(*it); StringVector line = StringUtil::split(*it," "); if (line.size() != 3) break; for (StringVector::iterator jt = line.begin(); jt != line.end(); ++jt) { mMatrix[i][j] = StringConverter::parseReal(*jt); j++; } i++; } } //------------------------------------------------------------------------- Matrix3 ColladaTLookAt::getMatrix3(void) const { return mMatrix; } //------------------------------------------------------------------------- Matrix4 ColladaTLookAt::getMatrix4(void) const { return Matrix4(getMatrix3()); } //------------------------------------------------------------------------- Vector3 ColladaTLookAt::getEye(void) const { return Vector3(mMatrix[0][0], mMatrix[0][1], mMatrix[0][2]); } //------------------------------------------------------------------------- Vector3 ColladaTLookAt::getTarget(void) const { return Vector3(mMatrix[1][0], mMatrix[1][1], mMatrix[1][2]); } //------------------------------------------------------------------------- Vector3 ColladaTLookAt::getUp(void) const { return Vector3(mMatrix[1][0], mMatrix[1][1], mMatrix[1][2]); } //------------------------------------------------------------------------- // ColladaTMatrix //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTMatrix::ColladaTMatrix(ColladaSceneNode *p) : ColladaTransform(p) { mMatrix = Matrix4::IDENTITY; } //------------------------------------------------------------------------- ColladaTMatrix::~ColladaTMatrix(void) { } //------------------------------------------------------------------------- void ColladaTMatrix::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; StringVector lines = StringUtil::split(content,"\r\n"); if (lines.size() != 4) return; uint i = 0; for (StringVector::iterator it = lines.begin(); it != lines.end(); ++it) { uint j = 0; StringUtil::trim(*it); StringVector line = StringUtil::split(*it," "); if (line.size() != 4) break; for (StringVector::iterator jt = line.begin(); jt != line.end(); ++jt) { mMatrix[i][j] = StringConverter::parseReal(*jt); j++; } i++; } } //------------------------------------------------------------------------- Matrix4 ColladaTMatrix::getMatrix4(void) const { return mMatrix; } //------------------------------------------------------------------------- // ColladaTPerspective //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTPerspective::ColladaTPerspective(ColladaSceneNode *p) : ColladaTransform(p) { mFOV = 90; } //------------------------------------------------------------------------- ColladaTPerspective::~ColladaTPerspective(void) { } //------------------------------------------------------------------------- void ColladaTPerspective::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; mFOV = StringConverter::parseReal(content); } //------------------------------------------------------------------------- Matrix4 ColladaTPerspective::getMatrix4(void) const { return Matrix4::IDENTITY; } //------------------------------------------------------------------------- // ColladaTRotate //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTRotate::ColladaTRotate(ColladaSceneNode *p) : ColladaTransform(p) { mAxis = Vector3::ZERO; mAngle = 0; } //------------------------------------------------------------------------- ColladaTRotate::~ColladaTRotate(void) { } //------------------------------------------------------------------------- void ColladaTRotate::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; StringVector line = StringUtil::split(content," "); if (line.size() != 4) return; mAxis.x = StringConverter::parseReal(line.at(0)); mAxis.y = StringConverter::parseReal(line.at(1)); mAxis.z = StringConverter::parseReal(line.at(2)); mAngle = StringConverter::parseReal(line.at(3)); } //------------------------------------------------------------------------- Matrix3 ColladaTRotate::getMatrix3(void) const { Matrix3 m = Matrix3::IDENTITY; m.FromAxisAngle(mAxis, Radian(Math::DegreesToRadians(mAngle))); return m; } //------------------------------------------------------------------------- Matrix4 ColladaTRotate::getMatrix4(void) const { return Matrix4(getMatrix3()); } //------------------------------------------------------------------------- // ColladaTScale //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTScale::ColladaTScale(ColladaSceneNode *p) : ColladaTransform(p) { mScale = Vector3::ZERO; } //------------------------------------------------------------------------- ColladaTScale::~ColladaTScale(void) { } //------------------------------------------------------------------------- void ColladaTScale::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; mScale = StringConverter::parseVector3(content); } //------------------------------------------------------------------------- Matrix3 ColladaTScale::getMatrix3(void) const { Matrix3 m = Matrix3::IDENTITY; m[0][0] = mScale.x; m[1][1] = mScale.y; m[2][2] = mScale.z; return m; } //------------------------------------------------------------------------- Matrix4 ColladaTScale::getMatrix4(void) const { Matrix4 m = Matrix4::IDENTITY; m.setScale(mScale); return m; } //------------------------------------------------------------------------- // ColladaTSkew //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTSkew::ColladaTSkew(ColladaSceneNode *p) : ColladaTransform(p) { mAngle = 0; mRotation = Vector3::ZERO; mTranslation = Vector3::ZERO; } //------------------------------------------------------------------------- ColladaTSkew::~ColladaTSkew(void) { } //------------------------------------------------------------------------- void ColladaTSkew::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; StringVector line = StringUtil::split(content," "); if (line.size() != 7) return; mAngle = StringConverter::parseReal(line.at(0)); mRotation.x = StringConverter::parseReal(line.at(1)); mRotation.y = StringConverter::parseReal(line.at(2)); mRotation.z = StringConverter::parseReal(line.at(3)); mTranslation.x = StringConverter::parseReal(line.at(4)); mTranslation.y = StringConverter::parseReal(line.at(5)); mTranslation.z = StringConverter::parseReal(line.at(6)); } //------------------------------------------------------------------------- Matrix3 ColladaTSkew::getMatrix3(void) const { return Matrix3::IDENTITY; } //------------------------------------------------------------------------- Matrix4 ColladaTSkew::getMatrix4(void) const { return Matrix4(getMatrix3()); } //------------------------------------------------------------------------- // ColladaTTranslate //------------------------------------------------------------------------- //------------------------------------------------------------------------- ColladaTTranslate::ColladaTTranslate(ColladaSceneNode *p) : ColladaTransform(p) { mTranslate = Vector3::ZERO; } //------------------------------------------------------------------------- ColladaTTranslate::~ColladaTTranslate(void) { } //------------------------------------------------------------------------- void ColladaTTranslate::doImport(xmlNode *node) { if (node == NULL) return; String content = ColladaUtils::getContentDirect(node); if (content.empty()) return; mTranslate = StringConverter::parseVector3(content); } //------------------------------------------------------------------------- Matrix4 ColladaTTranslate::getMatrix4(void) const { Matrix4 m = Matrix4::IDENTITY; m.makeTrans(mTranslate); return m; } }