Commits

Fred...@Baator  committed 4c065b3

added node axes and label
correct xforms still failing

  • Participants
  • Parent commits d9f9de7

Comments (0)

Files changed (9)

File media/3ds/amphimath_pillars.3DS

Binary file added.

File media/axes.mesh

Binary file added.

File ogre-lib3ds/MovableText.cpp

+/**
+* File: MovableText.cpp
+*
+* description: This create create a billboarding object that display a text.
+* 
+* @author  2003 by cTh see gavocanov@rambler.ru
+* @update  2006 by barraq see nospam@barraquand.com
+*/
+
+#include "precompiled.h"
+
+#include "Ogre.h"
+#include "OgreFontManager.h"
+#include "movableText.h"
+
+using namespace Ogre;
+
+#define POS_TEX_BINDING    0
+#define COLOUR_BINDING     1
+
+MovableText::MovableText(const String &name, const String &caption, const String &fontName, Real charHeight, const ColourValue &color)
+: mpCam(NULL)
+, mpWin(NULL)
+, mpFont(NULL)
+, mName(name)
+, mCaption(caption)
+, mFontName(fontName)
+, mCharHeight(charHeight)
+, mColor(color)
+, mType("MovableText")
+, mTimeUntilNextToggle(0)
+, mSpaceWidth(0)
+, mUpdateColors(true)
+, mOnTop(false)
+, mHorizontalAlignment(H_LEFT)
+, mVerticalAlignment(V_BELOW)
+, mGlobalTranslation(0.0)
+, mLocalTranslation(0.0)
+{
+    if (name == "")
+        throw Exception(Exception::ERR_INVALIDPARAMS, "Trying to create MovableText without name", "MovableText::MovableText");
+
+    if (caption == "")
+        throw Exception(Exception::ERR_INVALIDPARAMS, "Trying to create MovableText without caption", "MovableText::MovableText");
+
+    mRenderOp.vertexData = NULL;
+    this->setFontName(mFontName);
+    this->_setupGeometry();
+}
+
+MovableText::~MovableText()
+{
+    if (mRenderOp.vertexData)
+        delete mRenderOp.vertexData;
+    // May cause crashing... check this and comment if it does
+    if (!mpMaterial.isNull())
+        MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
+}
+
+void MovableText::setFontName(const String &fontName)
+{
+    if((Ogre::MaterialManager::getSingletonPtr()->resourceExists(mName + "Material"))) 
+    { 
+        Ogre::MaterialManager::getSingleton().remove(mName + "Material"); 
+    }
+
+    if (mFontName != fontName || mpMaterial.isNull() || !mpFont)
+    {
+        mFontName = fontName;
+        mpFont = (Font *)FontManager::getSingleton().getByName(mFontName).getPointer();
+        if (!mpFont)
+            throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + fontName, "MovableText::setFontName");
+
+        mpFont->load();
+        if (!mpMaterial.isNull())
+        {
+            MaterialManager::getSingletonPtr()->remove(mpMaterial->getName());
+            mpMaterial.setNull();
+        }
+
+        mpMaterial = mpFont->getMaterial()->clone(mName + "Material");
+        if (!mpMaterial->isLoaded())
+            mpMaterial->load();
+
+        mpMaterial->setDepthCheckEnabled(!mOnTop);
+        mpMaterial->setDepthBias(1.0,1.0);
+        mpMaterial->setDepthWriteEnabled(mOnTop);
+        mpMaterial->setLightingEnabled(false);
+        mNeedUpdate = true;
+    }
+}
+
+void MovableText::setCaption(const String &caption)
+{
+    if (caption != mCaption)
+    {
+        mCaption = caption;
+        mNeedUpdate = true;
+    }
+}
+
+void MovableText::setColor(const ColourValue &color)
+{
+    if (color != mColor)
+    {
+        mColor = color;
+        mUpdateColors = true;
+    }
+}
+
+void MovableText::setCharacterHeight(Real height)
+{
+    if (height != mCharHeight)
+    {
+        mCharHeight = height;
+        mNeedUpdate = true;
+    }
+}
+
+void MovableText::setSpaceWidth(Real width)
+{
+    if (width != mSpaceWidth)
+    {
+        mSpaceWidth = width;
+        mNeedUpdate = true;
+    }
+}
+
+void MovableText::setTextAlignment(const HorizontalAlignment& horizontalAlignment, const VerticalAlignment& verticalAlignment)
+{
+    if(mHorizontalAlignment != horizontalAlignment)
+    {
+        mHorizontalAlignment = horizontalAlignment;
+        mNeedUpdate = true;
+    }
+    if(mVerticalAlignment != verticalAlignment)
+    {
+        mVerticalAlignment = verticalAlignment;
+        mNeedUpdate = true;
+    }
+}
+
+void MovableText::setGlobalTranslation( Vector3 trans )
+{
+    mGlobalTranslation = trans;
+}
+
+void MovableText::setLocalTranslation( Vector3 trans )
+{
+    mLocalTranslation = trans;
+}
+
+void MovableText::showOnTop(bool show)
+{
+    if( mOnTop != show && !mpMaterial.isNull() )
+    {
+        mOnTop = show;
+        mpMaterial->setDepthBias(1.0,1.0);
+        mpMaterial->setDepthCheckEnabled(!mOnTop);
+        mpMaterial->setDepthWriteEnabled(mOnTop);
+    }
+}
+
+void MovableText::_setupGeometry()
+{
+    assert(mpFont);
+    assert(!mpMaterial.isNull());
+
+    unsigned int vertexCount = static_cast<unsigned int>(mCaption.size() * 6);
+
+    if (mRenderOp.vertexData)
+    {
+        // Removed this test as it causes problems when replacing a caption
+        // of the same size: replacing "Hello" with "hello"
+        // as well as when changing the text alignment
+        //if (mRenderOp.vertexData->vertexCount != vertexCount)
+        {
+            delete mRenderOp.vertexData;
+            mRenderOp.vertexData = NULL;
+            mUpdateColors = true;
+        }
+    }
+
+    if (!mRenderOp.vertexData)
+        mRenderOp.vertexData = new VertexData();
+
+    mRenderOp.indexData = 0;
+    mRenderOp.vertexData->vertexStart = 0;
+    mRenderOp.vertexData->vertexCount = vertexCount;
+    mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST; 
+    mRenderOp.useIndexes = false; 
+
+    VertexDeclaration  *decl = mRenderOp.vertexData->vertexDeclaration;
+    VertexBufferBinding   *bind = mRenderOp.vertexData->vertexBufferBinding;
+    size_t offset = 0;
+
+    // create/bind positions/tex.ccord. buffer
+    if (!decl->findElementBySemantic(VES_POSITION))
+        decl->addElement(POS_TEX_BINDING, offset, VET_FLOAT3, VES_POSITION);
+
+    offset += VertexElement::getTypeSize(VET_FLOAT3);
+
+    if (!decl->findElementBySemantic(VES_TEXTURE_COORDINATES))
+        decl->addElement(POS_TEX_BINDING, offset, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, 0);
+
+    HardwareVertexBufferSharedPtr ptbuf = HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(POS_TEX_BINDING),
+        mRenderOp.vertexData->vertexCount,
+        HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
+    bind->setBinding(POS_TEX_BINDING, ptbuf);
+
+    // Colours - store these in a separate buffer because they change less often
+    if (!decl->findElementBySemantic(VES_DIFFUSE))
+        decl->addElement(COLOUR_BINDING, 0, VET_COLOUR, VES_DIFFUSE);
+
+    HardwareVertexBufferSharedPtr cbuf = HardwareBufferManager::getSingleton().createVertexBuffer(decl->getVertexSize(COLOUR_BINDING),
+        mRenderOp.vertexData->vertexCount,
+        HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
+    bind->setBinding(COLOUR_BINDING, cbuf);
+
+    size_t charlen = mCaption.size();
+    float *pPCBuff = static_cast<float*>(ptbuf->lock(HardwareBuffer::HBL_DISCARD));
+
+    float largestWidth = 0;
+    float left = 0 * 2.0 - 1.0;
+    float top = -((0 * 2.0) - 1.0);
+
+    Real spaceWidth = mSpaceWidth;
+    // Derive space width from a capital A
+    if (spaceWidth == 0)
+        spaceWidth = mpFont->getGlyphAspectRatio('A') * mCharHeight * 2.0;
+
+    // for calculation of AABB
+    Ogre::Vector3 min, max, currPos;
+    Ogre::Real maxSquaredRadius;
+    bool first = true;
+
+    // Use iterator
+    String::iterator i, iend;
+    iend = mCaption.end();
+    bool newLine = true;
+    Real len = 0.0f;
+
+    Real verticalOffset = 0;
+    switch (mVerticalAlignment)
+    {
+    case MovableText::V_ABOVE:
+        verticalOffset = mCharHeight;
+        break;
+    case MovableText::V_CENTER:
+        verticalOffset = 0.5*mCharHeight;
+        break;
+    case MovableText::V_BELOW:
+        verticalOffset = 0;
+        break;
+    }
+    // Raise the first line of the caption
+    top += verticalOffset;
+    for (i = mCaption.begin(); i != iend; ++i)
+    {
+        if (*i == '\n')
+            top += verticalOffset * 2.0;
+    }
+
+    for (i = mCaption.begin(); i != iend; ++i)
+    {
+        if (newLine)
+        {
+            len = 0.0f;
+            for (String::iterator j = i; j != iend && *j != '\n'; j++)
+            {
+                if (*j == ' ')
+                    len += spaceWidth;
+                else 
+                    len += mpFont->getGlyphAspectRatio(*j) * mCharHeight * 2.0;
+            }
+            newLine = false;
+        }
+
+        if (*i == '\n')
+        {
+            left = 0 * 2.0 - 1.0;
+            top -= mCharHeight * 2.0;
+            newLine = true;
+            continue;
+        }
+
+        if (*i == ' ')
+        {
+            // Just leave a gap, no tris
+            left += spaceWidth;
+            // Also reduce tri count
+            mRenderOp.vertexData->vertexCount -= 6;
+            continue;
+        }
+
+        Real horiz_height = mpFont->getGlyphAspectRatio(*i);
+        Real u1, u2, v1, v2; 
+        Ogre::Font::UVRect utmp;
+        utmp = mpFont->getGlyphTexCoords(*i);
+        u1 = utmp.left;
+        u2 = utmp.right;
+        v1 = utmp.top;
+        v2 = utmp.bottom;
+
+        // each vert is (x, y, z, u, v)
+        //-------------------------------------------------------------------------------------
+        // First tri
+        //
+        // Upper left
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u1;
+        *pPCBuff++ = v1;
+
+        // Deal with bounds
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            currPos = Ogre::Vector3(left, top, -1.0);
+        else
+            currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
+        if (first)
+        {
+            min = max = currPos;
+            maxSquaredRadius = currPos.squaredLength();
+            first = false;
+        }
+        else
+        {
+            min.makeFloor(currPos);
+            max.makeCeil(currPos);
+            maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+        }
+
+        top -= mCharHeight * 2.0;
+
+        // Bottom left
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u1;
+        *pPCBuff++ = v2;
+
+        // Deal with bounds
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            currPos = Ogre::Vector3(left, top, -1.0);
+        else
+            currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
+        min.makeFloor(currPos);
+        max.makeCeil(currPos);
+        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+
+        top += mCharHeight * 2.0;
+        left += horiz_height * mCharHeight * 2.0;
+
+        // Top right
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u2;
+        *pPCBuff++ = v1;
+        //-------------------------------------------------------------------------------------
+
+        // Deal with bounds
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            currPos = Ogre::Vector3(left, top, -1.0);
+        else
+            currPos = Ogre::Vector3(left - (len / 2), top, -1.0);
+        min.makeFloor(currPos);
+        max.makeCeil(currPos);
+        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+
+        //-------------------------------------------------------------------------------------
+        // Second tri
+        //
+        // Top right (again)
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u2;
+        *pPCBuff++ = v1;
+
+        currPos = Ogre::Vector3(left, top, -1.0);
+        min.makeFloor(currPos);
+        max.makeCeil(currPos);
+        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+
+        top -= mCharHeight * 2.0;
+        left -= horiz_height  * mCharHeight * 2.0;
+
+        // Bottom left (again)
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u1;
+        *pPCBuff++ = v2;
+
+        currPos = Ogre::Vector3(left, top, -1.0);
+        min.makeFloor(currPos);
+        max.makeCeil(currPos);
+        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+
+        left += horiz_height  * mCharHeight * 2.0;
+
+        // Bottom right
+        if(mHorizontalAlignment == MovableText::H_LEFT)
+            *pPCBuff++ = left;
+        else
+            *pPCBuff++ = left - (len / 2);
+        *pPCBuff++ = top;
+        *pPCBuff++ = -1.0;
+        *pPCBuff++ = u2;
+        *pPCBuff++ = v2;
+        //-------------------------------------------------------------------------------------
+
+        currPos = Ogre::Vector3(left, top, -1.0);
+        min.makeFloor(currPos);
+        max.makeCeil(currPos);
+        maxSquaredRadius = std::max(maxSquaredRadius, currPos.squaredLength());
+
+        // Go back up with top
+        top += mCharHeight * 2.0;
+
+        float currentWidth = (left + 1)/2 - 0;
+        if (currentWidth > largestWidth)
+            largestWidth = currentWidth;
+    }
+
+    // Unlock vertex buffer
+    ptbuf->unlock();
+
+    // update AABB/Sphere radius
+    mAABB = Ogre::AxisAlignedBox(min, max);
+    mRadius = Ogre::Math::Sqrt(maxSquaredRadius);
+
+    if (mUpdateColors)
+        this->_updateColors();
+
+    mNeedUpdate = false;
+}
+
+void MovableText::_updateColors(void)
+{
+    assert(mpFont);
+    assert(!mpMaterial.isNull());
+
+    // Convert to system-specific
+    RGBA color;
+    Root::getSingleton().convertColourValue(mColor, &color);
+    HardwareVertexBufferSharedPtr vbuf = mRenderOp.vertexData->vertexBufferBinding->getBuffer(COLOUR_BINDING);
+    RGBA *pDest = static_cast<RGBA*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
+    for (int i = 0; i < (int)mRenderOp.vertexData->vertexCount; ++i)
+        *pDest++ = color;
+    vbuf->unlock();
+    mUpdateColors = false;
+}
+
+const Quaternion& MovableText::getWorldOrientation(void) const
+{
+    assert(mpCam);
+    return const_cast<Quaternion&>(mpCam->getDerivedOrientation());
+}
+
+// Add to build on Shoggoth:
+void MovableText::visitRenderables(Ogre::Renderable::Visitor* visitor, 
+                                   bool debugRenderables)
+{
+}
+
+const Vector3& MovableText::getWorldPosition(void) const
+{
+    assert(mParentNode);
+    return mParentNode->_getDerivedPosition();
+}
+
+void MovableText::getWorldTransforms(Matrix4 *xform) const 
+{
+    if (this->isVisible() && mpCam)
+    {
+        Matrix3 rot3x3, scale3x3 = Matrix3::IDENTITY;
+
+        // store rotation in a matrix
+        mpCam->getDerivedOrientation().ToRotationMatrix(rot3x3);
+
+        // parent node position
+        Vector3 ppos = mParentNode->_getDerivedPosition() + Vector3::UNIT_Y*mGlobalTranslation;
+        ppos += rot3x3*mLocalTranslation;
+
+        // apply scale
+        scale3x3[0][0] = mParentNode->_getDerivedScale().x / 2;
+        scale3x3[1][1] = mParentNode->_getDerivedScale().y / 2;
+        scale3x3[2][2] = mParentNode->_getDerivedScale().z / 2;
+
+        // apply all transforms to xform       
+        *xform = (rot3x3 * scale3x3);
+        xform->setTrans(ppos);
+    }
+}
+
+void MovableText::getRenderOperation(RenderOperation &op)
+{
+    if (this->isVisible())
+    {
+        if (mNeedUpdate)
+            this->_setupGeometry();
+        if (mUpdateColors)
+            this->_updateColors();
+        op = mRenderOp;
+    }
+}
+
+void MovableText::_notifyCurrentCamera(Camera *cam)
+{
+    mpCam = cam;
+}
+
+void MovableText::_updateRenderQueue(RenderQueue* queue)
+{
+    if (this->isVisible())
+    {
+        if (mNeedUpdate)
+            this->_setupGeometry();
+        if (mUpdateColors)
+            this->_updateColors();
+
+        queue->addRenderable(this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY);
+        //queue->addRenderable(this, mRenderQueueID, RENDER_QUEUE_SKIES_LATE);
+    }
+}

File ogre-lib3ds/MovableText.h

+/**
+* File: MovableText.h
+*
+* description: This create create a billboarding object that display a text.
+* 
+* @author  2003 by cTh see gavocanov@rambler.ru
+* @update  2006 by barraq see nospam@barraquand.com
+*/
+
+#ifndef __include_MovableText_H__
+#define __include_MovableText_H__
+
+namespace Ogre {
+
+    class MovableText : public MovableObject, public Renderable
+    {
+        /******************************** MovableText data ****************************/
+    public:
+        enum HorizontalAlignment    {H_LEFT, H_CENTER};
+        enum VerticalAlignment      {V_BELOW, V_ABOVE, V_CENTER};
+
+    protected:
+        String			mFontName;
+        String			mType;
+        String			mName;
+        String			mCaption;
+        HorizontalAlignment	mHorizontalAlignment;
+        VerticalAlignment	mVerticalAlignment;
+
+        ColourValue		mColor;
+        RenderOperation	mRenderOp;
+        AxisAlignedBox	mAABB;
+        LightList		mLList;
+
+        Real			mCharHeight;
+        Real			mSpaceWidth;
+
+        bool			mNeedUpdate;
+        bool			mUpdateColors;
+        bool			mOnTop;
+
+        Real			mTimeUntilNextToggle;
+        Real			mRadius;
+
+        Vector3            mGlobalTranslation;
+        Vector3            mLocalTranslation;
+
+        Camera			*mpCam;
+        RenderWindow	*mpWin;
+        Font			*mpFont;
+        MaterialPtr		mpMaterial;
+        MaterialPtr		mpBackgroundMaterial;
+
+        /******************************** public methods ******************************/
+    public:
+        MovableText(const String &name, const String &caption, const String &fontName = "BlueHighway", Real charHeight = 1.0, const ColourValue &color = ColourValue::White);
+        virtual ~MovableText();
+
+        // Add to build on Shoggoth:
+        virtual void visitRenderables(Ogre::Renderable::Visitor* visitor, bool debugRenderables = false);
+
+        // Set settings
+        void    setFontName(const String &fontName);
+        void    setCaption(const String &caption);
+        void    setColor(const ColourValue &color);
+        void    setCharacterHeight(Real height);
+        void    setSpaceWidth(Real width);
+        void    setTextAlignment(const HorizontalAlignment& horizontalAlignment, const VerticalAlignment& verticalAlignment);
+        void    setGlobalTranslation( Vector3 trans );
+        void    setLocalTranslation( Vector3 trans );
+        void    showOnTop(bool show=true);
+
+        // Get settings
+        const   String          &getFontName() const {return mFontName;}
+        const   String          &getCaption() const {return mCaption;}
+        const   ColourValue     &getColor() const {return mColor;}
+
+        Real    getCharacterHeight() const {return mCharHeight;}
+        Real    getSpaceWidth() const {return mSpaceWidth;}
+        Vector3    getGlobalTranslation() const {return mGlobalTranslation;}
+        Vector3    getLocalTranslation() const {return mLocalTranslation;}
+        bool    getShowOnTop() const {return mOnTop;}
+        AxisAlignedBox	        GetAABB(void) { return mAABB; }
+
+        /******************************** protected methods and overload **************/
+    protected:
+
+        // from MovableText, create the object
+        void	_setupGeometry();
+        void	_updateColors();
+
+        // from MovableObject
+        void    getWorldTransforms(Matrix4 *xform) const;
+        Real    getBoundingRadius(void) const {return mRadius;};
+        Real    getSquaredViewDepth(const Camera *cam) const {return 0;};
+        const   Quaternion        &getWorldOrientation(void) const;
+        const   Vector3           &getWorldPosition(void) const;
+        const   AxisAlignedBox    &getBoundingBox(void) const {return mAABB;};
+        const   String            &getName(void) const {return mName;};
+        const   String            &getMovableType(void) const {static Ogre::String movType = "MovableText"; return movType;};
+
+        void    _notifyCurrentCamera(Camera *cam);
+        void    _updateRenderQueue(RenderQueue* queue);
+
+        // from renderable
+        void    getRenderOperation(RenderOperation &op);
+        const   MaterialPtr       &getMaterial(void) const {assert(!mpMaterial.isNull());return mpMaterial;};
+        const   LightList         &getLights(void) const {return mLList;};
+    };
+
+#endif
+}

File ogre-lib3ds/Test3DSViewerApp.cpp

     mLightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("light node");
     mLightNode->attachObject(mLight);
     mLightNode->attachObject(mBBset);
-    mLightNode->setPosition(-300, 100, 200);
+    mLightNode->setPosition(-300, 100, -200);
     //mLightNode->setPosition(0, 100, 0);
     
 }
     //m3dsFile =  lib3ds_file_open("../media/3ds/test3.3DS");
     //m3dsFile =  lib3ds_file_open("../media/3ds/indochine.3DS");
     //m3dsFile =  lib3ds_file_open("../media/3ds/monaco.3DS");
-    m3dsFile =  lib3ds_file_open("../media/3ds/amphimath2.3DS");
+    //m3dsFile =  lib3ds_file_open("../media/3ds/amphimath_walls.3DS");
+    //m3dsFile =  lib3ds_file_open("../media/3ds/amphimath2.3DS");
+    m3dsFile =  lib3ds_file_open("../media/3ds/amphimath_pillars.3DS");
     //m3dsFile =  lib3ds_file_open("../media/3ds/Modern-home-interior1.3DS");
+    //m3dsFile =  lib3ds_file_open("../media/3ds/test_pivot2.3DS");
     if (!m3dsFile->nodes)
         lib3ds_file_create_nodes_for_meshes(m3dsFile);
 
     lib3ds_file_eval(m3dsFile, 0);
 
     _createMeshesFrom3dsFile(m3dsFile);
-    _buildSceneFromNode(m3dsFile->nodes, modelNode, "/");
-   
+    _buildSceneFromNode(m3dsFile->nodes, modelNode, "/", 0);
+
     //_buildSubtree( m3dsFile->nodes, "/", modelNode);
 
     modelNode->scale(0.1, 0.1, 0.1);
             m3dsBuildLog->logMessage(boost::str(boost::format("building new node (%d) : %s") % mNodeCnt % fullName));
 
             SceneNode *newNode = _parentNode->createChildSceneNode(fullName + " Node");
-
-
-            //m3dsBuildLog->logMessage("pivot : " + StringConverter::toString(Vector3(n->pivot[0], n->pivot[1], n->pivot[2])));
-            //
-            //Matrix4 M;
-            //for(int i=0 ; i<4 ; ++i)
-            //    for(int j=0 ; j<4 ; ++j)
-            //        M[i][j] = n->base.matrix[j][i];
-
-
-            //m3dsBuildLog->logMessage("base matrix: " + StringConverter::toString(M));
-            //
-            //Quaternion q(n->rot[0], n->rot[1], n->rot[2], n->rot[3]);
-
-            //m3dsBuildLog->logMessage("rotation : " + StringConverter::toString(q));
-
-            //Vector3 pos(n->pos);
-
-            //m3dsBuildLog->logMessage("position : " + StringConverter::toString(pos));
-
-
-
             Lib3dsMesh *mesh = lib3ds_file_mesh_for_node(m3dsFile, (Lib3dsNode*)n);
             
             if(mesh && mesh->nvertices)
                     newNode->attachObject(ent);
                 }
             }
-            
             _buildSubtree(p->childs, fullName, newNode);
         }
+        
     }
 }
 //------------------------------------------------------------------------------
         //int i;
 
         lib3ds_matrix_copy(M, node->base.matrix);
-        //lib3ds_matrix_translate(M, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
+        lib3ds_matrix_translate(M, -node->pivot[0], -node->pivot[1], -node->pivot[2]);
         lib3ds_matrix_copy(inv_matrix, mesh->matrix);
         lib3ds_matrix_inv(inv_matrix);
         lib3ds_matrix_mult(M, M, inv_matrix);
 //------------------------------------------------------------------------------
 void Test3DSViewerApp::_createMeshesFrom3dsFile(Lib3dsFile *_3dsfile)
 {
+    m3dsBuildLog->logMessage("----------------  building meshes");
     for(int i=0 ; i<_3dsfile->nmeshes ; ++i)
     {
         Lib3dsMesh *mesh = _3dsfile->meshes[i];
-        ManualObject *newObject = mSceneMgr->createManualObject(mesh->name);
+        ManualObject *newObject = mSceneMgr->createManualObject(boost::str(boost::format("%d_%s")% i % mesh->name));
 
-
+        m3dsBuildLog->logMessage(std::string("building new mesh : ") + newObject->getName());
 
         float (*orig_vertices)[3];
         orig_vertices = (float(*)[3])malloc(sizeof(float) * 3 * mesh->nvertices);
         float (*normals)[3] = (float(*)[3])malloc(sizeof(float) * 9 * mesh->nfaces);
         lib3ds_mesh_calculate_vertex_normals(mesh, normals);
 
-
         // create an ogre object for easy OgreMesh conversion
         // Gray = default material
         // TODO: better default material
         // foreach tri
         for(int tri_idx = 0 ; tri_idx < mesh->nfaces ; ++tri_idx)
         {
-
             // foreach vertex in tri
             for(int j=0 ; j<3 ; ++j)
             {
                 newObject->position(pos);
 
                 if(mesh->texcos)
+                {
                     tc = Vector2(mesh->texcos[mesh->faces[tri_idx].index[j]]);
+                    newObject->textureCoord(tc);
+                }
+
                 norm = Vector3(normals[idx]);
 
-
                 newObject->normal(norm);
-
                 newObject->index(idx++);
             }
         }
 
         newObject->end();
         free(normals); 
-        //}
         //restore mesh for future use
         memcpy(mesh->vertices, orig_vertices, sizeof(float) * 3 * mesh->nvertices);
         free(orig_vertices);
         MeshPtr newMesh;
         if(idx)
         {
-            // create ogre mesh from manualobject
-            newMesh = newObject->convertToMesh(mesh->name);
-            //newMesh->buildTangentVectors();
-            
+            boost::format fmt("creating new Ogre::Mesh %s [%d vertices]");
+            fmt % mesh->name % idx;
+            m3dsBuildLog->logMessage(fmt.str());
+
+            newMesh = newObject->convertToMesh(newObject->getName());
+            newMesh->buildEdgeList();
         }
         else
+        {
+            boost::format fmt("mesh %s had %d vertices");
+            fmt % mesh->name % idx;
+            m3dsBuildLog->logMessage(fmt.str());
             newMesh.setNull();
+        }
 
         mSceneMgr->destroyManualObject(newObject);
         mCenteredMeshes[mesh->name] = newMesh;
     }
+    m3dsBuildLog->logMessage("----------------  building meshes ended");
 }
 //------------------------------------------------------------------------------
-void Test3DSViewerApp::_buildSceneFromNode(Lib3dsNode *_3dsNode, SceneNode *_parentNode, const std::string &_basename)
+void Test3DSViewerApp::_buildSceneFromNode(Lib3dsNode *_3dsNode, SceneNode *_parentNode
+                                           ,const std::string &_basename
+                                           ,int _level)
 {
     boost::format fullNameFmt("%s/%06d%s");
     Lib3dsNode *p;
+    SceneNode *newNode;
     for(p = _3dsNode ; p ; p=p->next)
     {
+        std::stringstream spaces;
+        for(int i=0 ; i<_level ; ++i)
+            spaces << " ";
+        boost::format fmt("%s (%d) \t %s \t [%s]");
+        fmt % spaces.str() % p->node_id % p->name;
+        switch(p->type)
+        {
+        case LIB3DS_NODE_AMBIENT_COLOR:    fmt % "Ambient Color"; break;
+        case LIB3DS_NODE_MESH_INSTANCE:    fmt % "Mesh Instance"; break;
+        case LIB3DS_NODE_CAMERA:           fmt % "Camera"; break;
+        case LIB3DS_NODE_CAMERA_TARGET:    fmt % "Camera Target"; break;
+        case LIB3DS_NODE_OMNILIGHT:        fmt % "Omnilight"; break;
+        case LIB3DS_NODE_SPOTLIGHT:        fmt % "Spotlight"; break;
+        case LIB3DS_NODE_SPOTLIGHT_TARGET: fmt % "Spotlight Target"; break;
+        default: break;
+        }
+
+        m3dsBuildLog->logMessage(fmt.str());
+        
+        m3dsBuildLog->logMessage(spaces.str() + "    matrix[4][4] : ");
+        for(int i=0 ; i<4 ; ++i)
+        {
+            std::stringstream matrixLine;
+            boost::format matrixLineFmt("%s%s %+.2f   %+.2f   %+.2f   %+.2f");
+            matrixLineFmt % spaces.str() % "    ";
+            matrixLineFmt   % p->matrix[0][i] % p->matrix[1][i]
+                            % p->matrix[2][i] % p->matrix[3][i];
+            m3dsBuildLog->logMessage(matrixLineFmt.str());
+        }
+
+        
 
         if (p->type == LIB3DS_NODE_MESH_INSTANCE) 
         {
 
             Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*) p;
 
-            m3dsBuildLog->logMessage(boost::str(boost::format("building new node (%d) : %s") % mNodeCnt % fullName));
+            //m3dsBuildLog->logMessage(boost::str(boost::format("building new node (%d) : %s") % mNodeCnt % fullName));
 
-            SceneNode *newNode = _parentNode->createChildSceneNode(fullName + " Node");
+            newNode = _parentNode->createChildSceneNode(fullName + " Node");
+                 
+            SceneNode *nodeCenter = newNode->createChildSceneNode(fullName + " NodeCenter");
+            Entity *nodeSphere = mSceneMgr->createEntity(fullName + "sphere", "axes.mesh");
+            //nodeSphere->setMaterialName("Gray");
+            nodeCenter->attachObject(nodeSphere);
+            float scale = 20.0 / nodeSphere->getBoundingBox().getSize().x;
+            nodeCenter->setScale(scale, scale, scale);
+
+            MovableTextPtr nodeLabel(new MovableText(fullName, std::string(p->name)));
+            nodeLabel->setTextAlignment(MovableText::H_CENTER, MovableText::V_BELOW);
+            nodeLabel->setCharacterHeight(7);
+            nodeLabel->setVisible(true);
+            nodeLabel->showOnTop(true);
             
-            newNode->translate(-n->pivot[0], -n->pivot[1], -n->pivot[2]);
+            //nodeLabel = newObject.ObjectNode->createChildSceneNode(name+"labelnode", Vector3(0, 120, 0));
+            nodeCenter->attachObject(&(*nodeLabel));
+            mNodeLabels[fullName] = nodeLabel;
+
+
+
+
+
+            //newNode->translate(n->pos[0], n->pos[1], n->pos[2]);
+            newNode->scale(n->scl[0], n->scl[1], n->scl[2]);
+            newNode->rotate(Quaternion(n->rot[3], n->rot[0], n->rot[1], n->rot[2]));
             
-            newNode->rotate(Quaternion(n->rot[3], n->rot[0], n->rot[1], n->rot[2]));
-            newNode->translate(n->pos[0], n->pos[1], n->pos[2]);
-            newNode->setScale(n->scl[0], n->scl[1], n->scl[2]);
+           
+            //newNode->translate(-n->pivot[0], -n->pivot[1], -n->pivot[2]);
+
+            //newNode->setVisible((bool)n->hide);
+
+
+            // log node xforms
+            m3dsBuildLog->logMessage(spaces.str() + "    pivot : "
+                                                  + StringConverter::toString(Vector3(-n->pivot[0]
+                                                                                     ,-n->pivot[1]
+                                                                                     , -n->pivot[2])));
+
+            m3dsBuildLog->logMessage(spaces.str() + "    mesh instance transform : ");
+            Vector3 pos, scl;
+            Quaternion rot;
+            scl = Vector3(n->scl[0], n->scl[1], n->scl[2]);
+            pos = Vector3(n->pos[0], n->pos[1], n->pos[2]);
+            rot = Quaternion(n->rot[3], n->rot[0], n->rot[1], n->rot[2]);
+
+            Matrix4 M;
+            M.makeTransform(pos, scl, rot);
+            for(int i=0 ; i<4 ; ++i)
+            {
+                std::stringstream matrixLine;
+                boost::format matrixLineFmt("%s%s %+.2f   %+.2f   %+.2f   %+.2f");
+                matrixLineFmt % spaces.str() % "    ";
+                matrixLineFmt   % M[i][0] % M[i][1] % M[i][2] % M[i][3];
+                m3dsBuildLog->logMessage(matrixLineFmt.str());
+            }
+
 
             
             Lib3dsMesh *mesh = lib3ds_file_mesh_for_node(m3dsFile, (Lib3dsNode*)n);
             {
                 std::string meshName = mesh->name;
 
+                // log mesh xforms
+                m3dsBuildLog->logMessage(spaces.str() + "    mesh matrix : ");
+                for(int i=0 ; i<4 ; ++i)
+                {
+                    std::stringstream matrixLine;
+                    boost::format matrixLineFmt("%s%s %+.2f   %+.2f   %+.2f   %+.2f");
+                    matrixLineFmt % spaces.str() % "    ";
+                    matrixLineFmt   % mesh->matrix[0][i] % mesh->matrix[1][i]
+                                    % mesh->matrix[2][i] % mesh->matrix[3][i];
+                    m3dsBuildLog->logMessage(matrixLineFmt.str());
+                }
+
+
                 MeshPtr meshToAdd = mCenteredMeshes[meshName];
                 if(! meshToAdd.isNull())
                 {
-                    m3dsBuildLog->logMessage(boost::str(boost::format("attaching %s to node %s")% mCenteredMeshes[meshName]->getName() % fullName));
+                    //m3dsBuildLog->logMessage(boost::str(boost::format("attaching %s to node %s")% mCenteredMeshes[meshName]->getName() % fullName));
                     Entity *ent = mSceneMgr->createEntity(fullName+" Ent", mCenteredMeshes[meshName]->getName());
                     newNode->attachObject(ent);
                 }
             }
-    
-            /*Matrix4 M;
-            M.makeTransform()*/
-            _buildSceneFromNode(p->childs, newNode, fullName);
+
+            m3dsBuildLog->logMessage("\n\n");
+
+            _buildSceneFromNode(p->childs, newNode, fullName, _level+1);
         }
-        //else if(p->type == LIB3DS_NODE_OMNILIGHT)
-        //{
-        //    //...
-        //}
     }
 }
 //------------------------------------------------------------------------------

File ogre-lib3ds/Test3DSViewerApp.h

 #include <cstdio>
 #include <cstring>
 
+#include <boost/shared_ptr.hpp>
+#include <lib3ds.h>
 #include <Ogre.h>
+
+
+#include "MovableText.h"
 #include "ExampleApplication.h"
 
-#include <lib3ds.h>
+
     
 
 using namespace Ogre;
 
     void _createMeshesFrom3dsFile(Lib3dsFile*);
     void _buildSceneFromNode(Lib3dsNode*, SceneNode*
-                            ,const std::string&);
+                            ,const std::string&
+                            ,int);
 
 protected:
     FILE *mFile;
     Log *m3dsBuildLog;
     int mDummyCnt, mNodeCnt;
 
+    typedef boost::shared_ptr<MovableText> MovableTextPtr;
     std::map<std::string, MeshPtr> mCenteredMeshes;
+    std::map<std::string, MovableTextPtr> mNodeLabels;
 
 };

File ogre-lib3ds/TextRenderer.cpp

+#include "precompiled.h"
+
+#include "TextRenderer.h"
+
+template<> TextRenderer* Ogre::Singleton<TextRenderer>::ms_Singleton = 0;
+
+TextRenderer::TextRenderer()
+{
+    _overlayMgr = Ogre::OverlayManager::getSingletonPtr();
+
+    _overlay = _overlayMgr->create("overlay1");
+    _panel = static_cast<Ogre::OverlayContainer*>(_overlayMgr->createOverlayElement("Panel", "container1"));
+    _panel->setDimensions(1, 1);
+    _panel->setPosition(0, 0);
+
+    _overlay->add2D(_panel);
+
+    _overlay->show();
+}
+
+void TextRenderer::addTextBox(const std::string& ID,
+                              const std::string& text,
+                              Ogre::Real x, Ogre::Real y,
+                              Ogre::Real width, Ogre::Real height,
+                              const Ogre::ColourValue& color)
+{
+    Ogre::OverlayElement* textBox = _overlayMgr->createOverlayElement("TextArea", ID);
+    textBox->setDimensions(width, height);
+    textBox->setMetricsMode(Ogre::GMM_PIXELS);
+    textBox->setPosition(x, y);
+    textBox->setWidth(width);
+    textBox->setHeight(height);
+    textBox->setParameter("font_name", "MyFont");
+    textBox->setParameter("char_height", "16");
+    textBox->setColour(color);
+
+    textBox->setCaption(text);
+
+    _panel->addChild(textBox);
+}
+
+void TextRenderer::removeTextBox(const std::string& ID)
+{
+    _panel->removeChild(ID);
+    _overlayMgr->destroyOverlayElement(ID);
+}
+
+void TextRenderer::setText(const std::string& ID, const std::string& Text)
+{
+    Ogre::OverlayElement* textBox = _overlayMgr->getOverlayElement(ID);
+    textBox->setCaption(Text);
+}

File ogre-lib3ds/TextRenderer.h

+#ifndef TextRenderer_h__
+#define TextRenderer_h__
+
+#include <Ogre.h>
+#include <OgreSingleton.h>
+
+class TextRenderer : public Ogre::Singleton<TextRenderer>
+{
+private:
+
+    Ogre::OverlayManager*    _overlayMgr;
+    Ogre::Overlay*           _overlay;
+    Ogre::OverlayContainer*  _panel;
+
+public:
+
+    TextRenderer();
+    ~TextRenderer();
+
+    void addTextBox(
+        const std::string& ID,
+        const std::string& text,
+        Ogre::Real x, Ogre::Real y,
+        Ogre::Real width, Ogre::Real height,
+        const Ogre::ColourValue& color = Ogre::ColourValue(1.0, 1.0, 1.0, 1.0));
+
+    void removeTextBox(const std::string& ID);
+
+    void setText(const std::string& ID, const std::string& Text);
+
+    void setPosition(Ogre::Real _left, Ogre::Real _top)
+    {
+        _panel->setPosition(_left, _top);
+    }
+};
+#endif // TextRenderer_h__

File ogre-lib3ds/ogre-lib3ds.vcproj

 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
+				RelativePath=".\MovableText.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\ogre-lib3ds.cpp"
 				>
 			</File>
 				RelativePath=".\Test3DSViewerApp.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\TextRenderer.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"
 				>
 			</File>
 			<File
+				RelativePath=".\MovableText.h"
+				>
+			</File>
+			<File
 				RelativePath=".\precompiled.h"
 				>
 			</File>
 				RelativePath=".\Test3DSViewerApp.h"
 				>
 			</File>
+			<File
+				RelativePath=".\TextRenderer.h"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"