Commits

Frederic De Groef committed 92d6ee9

refactorized MeshData, EdgeGeometryBuilder

  • Participants
  • Parent commits 2e36d0f

Comments (0)

Files changed (7)

File ogre-npr/EdgeGeometryBuilder.cpp

+#include "precompiled.h"
+#include "EdgeGeometryBuilder.hpp"
+
+
+//-----------------------------------------------------------------------------
+EdgeGeometryBuilder::EdgeGeometryBuilder(Ogre::Log *_log, Ogre::SceneManager *_sceneMgr)
+    :mLog(_log)
+    ,mSceneMgr(_sceneMgr)
+    ,mIsBuilding(false)
+    ,mIsVisible(false)
+    ,mEdges(NULL)
+    ,mRidgeThreshold(10.0f)
+{
+}
+//-----------------------------------------------------------------------------
+EdgeGeometryBuilder::~EdgeGeometryBuilder()
+{
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::attachToSceneNode(Ogre::SceneNode *_node)
+{
+    _node->attachObject(mEdges);
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::setVisible(bool _visible)
+{
+#ifdef _DEBUG
+    assert(mEdges);
+#endif
+
+    mEdges->setVisible(_visible);
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::begin()
+{
+    mIsBuilding = true;
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::end()
+{
+    mIsBuilding = false;
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::addEdgesForEntity(Ogre::Entity *_ent)
+{
+    mLog->logMessage("Creating edges for entity : " + _ent->getName());
+
+    Ogre::MeshPtr mesh = _ent->getMesh();
+
+    {
+        boost::format fmt("Mesh has %d submeshes");
+        fmt % mesh->getNumSubMeshes();
+        mLog->logMessage(fmt.str());
+    }
+
+    //mesh->getSubMesh(0)->setBuildEdgesEnabled(true);
+    //mesh->getSubMesh(1)->setBuildEdgesEnabled(true);
+
+    mesh->buildEdgeList();
+
+    Ogre::EdgeData *edgeData = mesh->getEdgeList();
+
+    {
+        boost::format fmt("Generating %d edgegroups");
+        fmt % edgeData->edgeGroups.size();
+        mLog->logMessage(fmt.str());
+    }
+
+    mEdges = mSceneMgr->createManualObject(_ent->getName() + "edges");
+    mMeshData = new MeshData(mesh,  Ogre::Vector3::ZERO, Ogre::Quaternion::IDENTITY, Ogre::Vector3::UNIT_SCALE);
+
+
+    mEdges->begin("NPR/EdgeOutliner", Ogre::RenderOperation::OT_TRIANGLE_LIST);
+
+    mIndex = 0;
+    for(int edgeGroupIdx = 0 ; edgeGroupIdx < edgeData->edgeGroups.size() ; edgeGroupIdx++)
+    {
+        {
+            boost::format fmt("Adding edges for edgegroup[%d]");
+            fmt % edgeGroupIdx ;
+            mLog->logMessage(fmt.str());
+        }
+
+        Ogre::EdgeData::EdgeGroup &currentEdgeGroup = edgeData->edgeGroups[edgeGroupIdx];
+        _addEdgesForEdgeGroup(currentEdgeGroup, *edgeData);
+
+        {
+            boost::format fmt("%s : Added %d edges (%d tris, %d vertices)");
+            fmt % mEdges->getName() % (mIndex/6) % (mIndex/3) % (mIndex);
+            mLog->logMessage(fmt.str());
+        }
+
+    }
+    mEdges->end();
+
+    delete mMeshData;
+    mMeshData = NULL;
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::_addEdgesForEdgeGroup(const Ogre::EdgeData::EdgeGroup &_edgeGroup, const Ogre::EdgeData &edgeData)
+{
+    int edgeCount = _edgeGroup.edges.size();
+                                                            
+    for(int i=0; i<edgeCount ; i++)
+    {
+        Ogre::EdgeData::Edge e = _edgeGroup.edges[i];
+
+        Ogre::Vector3 v0, v1;
+        Ogre::Vector4 nA, nB ;
+        Ogre::Real markedEdge;
+
+        if(e.degenerate)
+        {
+            v0 =  mMeshData->getVertex(e.vertIndex[0]);
+            v1 =  mMeshData->getVertex(e.vertIndex[1]);
+
+            nA = edgeData.triangleFaceNormals[e.triIndex[0]];
+            nB = -nA;
+            markedEdge = 2.0f;
+        }
+        else
+        {
+            v0 =  mMeshData->getVertex(e.vertIndex[0]);
+            v1 =  mMeshData->getVertex(e.vertIndex[1]);
+
+            nA = edgeData.triangleFaceNormals[e.triIndex[0]];
+            nB = edgeData.triangleFaceNormals[e.triIndex[1]];
+
+            Ogre::Real ridgeThreshold = Ogre::Degree(mRidgeThreshold).valueRadians();
+            Ogre::Real valleyThreshold = Ogre::Degree(mRidgeThreshold).valueRadians();
+
+
+            bool isRidge = _isEdgeARidge(Ogre::Vector3(nA.x, nA.y, nA.z)
+                                        ,Ogre::Vector3(nB.x, nB.y, nB.z)
+                                        ,ridgeThreshold);
+
+            bool isValley = _isEdgeAValley(Ogre::Vector3(nA.x, nA.y, nA.z)
+                                          ,Ogre::Vector3(nB.x, nB.y, nB.z)
+                                          ,valleyThreshold);
+
+            markedEdge = (isRidge || isValley) ? 1.0f : 0.0f;
+        }
+
+        {
+            boost::format fmt("Adding new edge for position : (%.2f, %.2f, %.2f)  (%.2f, %.2f, %.2f)");
+            fmt % v0.x % v0.y % v0.z % v1.x % v1.y % v0.z; 
+            mLog->logMessage(fmt.str());
+        }
+
+        _buildEdgeQuad(v0, v1, nA, nB, markedEdge, mIndex);
+        mIndex += 6;
+    }
+}
+//-----------------------------------------------------------------------------
+void EdgeGeometryBuilder::_buildEdgeQuad(  const Ogre::Vector3 &_v0, const Ogre::Vector3 &_v1
+                                         , const Ogre::Vector4 &_nA,const Ogre::Vector4 &_nB
+                                         , const Ogre::Real _markedEdge,unsigned int _idx)
+{
+    Ogre::Vector3 nA = Ogre::Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
+    Ogre::Vector3 nB = Ogre::Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
+
+    /* 1st tri
+    1 __ 2
+    | /
+    |/
+    3
+    */
+    mEdges->position(_v0);
+    mEdges->normal(nA);
+    mEdges->textureCoord(nB);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+
+    mEdges->position(_v0);
+    mEdges->normal(nB);
+    mEdges->textureCoord(nA);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+
+    mEdges->position(_v1);
+    mEdges->normal(nA);
+    mEdges->textureCoord(nB);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+
+    /* 2nd tri
+       6
+      /|
+     /_|
+    4   5
+    */
+    mEdges->position(_v1);
+    mEdges->normal(nA);
+    mEdges->textureCoord(nB);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+
+    mEdges->position(_v0);
+    mEdges->normal(nB);
+    mEdges->textureCoord(nA);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+
+    mEdges->position(_v1);
+    mEdges->normal(nB);
+    mEdges->textureCoord(nA);
+    mEdges->textureCoord(_markedEdge);
+
+    mEdges->index(_idx++);
+}
+
+//-----------------------------------------------------------------------------
+bool EdgeGeometryBuilder::_isEdgeARidge(const Ogre::Vector3 &_nA, const Ogre::Vector3 &_nB, const Ogre::Real &_threshold)
+{
+    Ogre::Vector3 nA_norm = Ogre::Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
+    Ogre::Vector3 nB_norm = Ogre::Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
+
+    return nA_norm.dotProduct(nB_norm) < Ogre::Math::Cos(_threshold);
+}
+//-----------------------------------------------------------------------------
+bool EdgeGeometryBuilder::_isEdgeAValley(const Ogre::Vector3 &_nA, const Ogre::Vector3 &_nB, const Ogre::Real &_threshold)
+{
+    Ogre::Vector3 nA_norm = Ogre::Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
+    Ogre::Vector3 nB_norm = Ogre::Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
+
+    return nA_norm.dotProduct(nB_norm) < Ogre::Math::Cos(_threshold);
+}

File ogre-npr/EdgeGeometryBuilder.hpp

+#pragma once
+#ifndef __041010_EDGEGEOMETRYBUILDER_HPP__
+#define __041010_EDGEGEOMETRYBUILDER_HPP__
+
+#include <Ogre.h>
+#include "MeshData.hpp"
+class EdgeGeometryBuilder
+{
+public:
+    EdgeGeometryBuilder(Ogre::Log *_log, Ogre::SceneManager *_sceneMgr);
+    ~EdgeGeometryBuilder();
+    void begin();
+    void addEdgesForEntity(Ogre::Entity *_ent);
+    void end();
+    void attachToSceneNode(Ogre::SceneNode*);
+    void setVisible(bool _visible);
+
+
+protected:
+    void _addEdgesForEdgeGroup(const Ogre::EdgeData::EdgeGroup &_edgeGroup
+                              ,const Ogre::EdgeData &edgeData);
+    void _buildEdgeQuad(const Ogre::Vector3 &_v0, const Ogre::Vector3 &_v1
+                       ,const Ogre::Vector4 &_nA, const Ogre::Vector4 &_nB
+                       ,const Ogre::Real _markedEdge, unsigned int _idx);
+
+    inline bool _isEdgeARidge(const Ogre::Vector3&, const Ogre::Vector3&, const Ogre::Real&);
+    inline bool _isEdgeAValley(const Ogre::Vector3&, const Ogre::Vector3&, const Ogre::Real&);
+
+
+private:
+    EdgeGeometryBuilder(){};
+
+
+protected:
+    bool mIsBuilding;
+    bool mIsVisible;
+    Ogre::ManualObject *mEdges;
+    Ogre::Log *mLog;
+    Ogre::SceneManager *mSceneMgr;
+    Ogre::Real mRidgeThreshold;
+
+    MeshData *mMeshData;
+    int mIndex;
+};
+
+#endif 

File ogre-npr/MeshData.cpp

+#include "precompiled.h"
+#include "MeshData.hpp"
+
+
+//-----------------------------------------------------------------------------
+MeshData::MeshData(Ogre::MeshPtr _mesh
+                   , const Ogre::Vector3 &_pos
+                   , const Ogre::Quaternion &_orient
+                   , const Ogre::Vector3 &_scale)
+    :mMesh(_mesh)
+    ,mPosition(_pos)
+    ,mScale(_scale)
+    ,mRotation(_orient)
+{
+    _getMeshInformation();
+}
+//-----------------------------------------------------------------------------
+MeshData::~MeshData(){}
+//-----------------------------------------------------------------------------
+void MeshData::_getMeshInformation()
+{
+    added_shared = false;
+    current_offset = 0;
+    shared_offset = 0;
+    next_offset = 0;
+    index_offset = 0;
+
+    _initBuffers();
+
+
+    // Run through the submeshes again, adding the data into the arrays
+    for ( unsigned short i = 0; i < mMesh->getNumSubMeshes(); ++i)
+    {
+
+        _extractVertexData(mMesh->getSubMesh(i));
+        _extractIndexBuffer(mMesh->getSubMesh(i));
+    }
+} 
+//-----------------------------------------------------------------------------
+void MeshData::_extractBufferSizes()
+{
+    // Calculate how many vertices and indices we're going to need
+    for (unsigned short i = 0; i < mMesh->getNumSubMeshes(); ++i)
+    {
+        Ogre::SubMesh* submesh = mMesh->getSubMesh( i );
+
+        // We only need to add the shared vertices once
+        if(submesh->useSharedVertices)
+        {
+            if( !added_shared )
+            {
+                mVertexCount += mMesh->sharedVertexData->vertexCount;
+                added_shared = true;
+            }
+        }
+        else
+        {
+            mVertexCount += submesh->vertexData->vertexCount;
+        }
+
+        mIndexCount += submesh->indexData->indexCount;
+    }
+}
+//-----------------------------------------------------------------------------
+void MeshData::_initBuffers()
+{
+    mVertexCount = 0;
+    mIndexCount = 0;
+
+    _extractBufferSizes();
+
+    mVertices.resize(mVertexCount);
+    mNormals.resize(mVertexCount);
+    mIndices.resize(mIndexCount);
+}
+//-----------------------------------------------------------------------------
+void MeshData::_extractVertexData(Ogre::SubMesh* submesh)
+{
+    Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mMesh->sharedVertexData : submesh->vertexData;
+
+    if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
+    {
+        if(submesh->useSharedVertices)
+        {
+            added_shared = true;
+            shared_offset = current_offset;
+        }
+        _extractPositions(vertex_data);
+        _extractNormals(vertex_data);
+        next_offset += vertex_data->vertexCount;
+
+    }
+}
+//-----------------------------------------------------------------------------
+void MeshData::_extractPositions(Ogre::VertexData *_vertexdata)
+{
+    const Ogre::VertexElement* posElem =
+        _vertexdata->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
+
+    Ogre::HardwareVertexBufferSharedPtr vbuf =
+        _vertexdata->vertexBufferBinding->getBuffer(posElem->getSource());
+
+    unsigned char* vertex =
+        static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
+
+    // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
+    //  as second argument. So make it float, to avoid trouble when Ogre::Real will
+    //  be comiled/typedefed as double:
+    //      Ogre::Real* pReal;
+    float* pReal;
+
+    for( size_t j = 0; j < _vertexdata->vertexCount; ++j, vertex += vbuf->getVertexSize())
+    {
+        posElem->baseVertexPointerToElement(vertex, &pReal);
+
+        Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);
+
+        mVertices[current_offset + j] = (mRotation * (pt * mScale)) + mPosition;
+    }
+    vbuf->unlock();
+}
+//-----------------------------------------------------------------------------
+void MeshData::_extractNormals(Ogre::VertexData *_vertexdata)
+{
+    const Ogre::VertexElement* normalElem =
+        _vertexdata->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);
+
+    Ogre::HardwareVertexBufferSharedPtr vbuf =
+        _vertexdata->vertexBufferBinding->getBuffer(normalElem->getSource());
+
+    unsigned char* normal =
+        static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
+
+    float* pReal;
+    for( size_t j = 0; j < _vertexdata->vertexCount; ++j, normal += vbuf->getVertexSize())
+    {
+        normalElem->baseVertexPointerToElement(normal, &pReal);
+        Ogre::Vector3 normal(pReal[0], pReal[1], pReal[2]);
+        mNormals[current_offset + j] = (mRotation * (normal));
+    }
+    vbuf->unlock();
+
+}
+//-----------------------------------------------------------------------------
+void MeshData::_extractIndexBuffer(Ogre::SubMesh *_submesh)
+{
+    Ogre::IndexData* index_data = _submesh->indexData;
+    size_t numTris = index_data->indexCount / 3;
+    Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
+
+    bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
+
+    unsigned long*  pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
+    unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
+
+
+    size_t offset = (_submesh->useSharedVertices)? shared_offset : current_offset;
+
+    // Ogre 1.6 patch (commenting the static_cast...) - index offsets start from 0 for each submesh
+    if ( use32bitindexes )
+    {
+        for ( size_t k = 0; k < numTris*3; ++k)
+        {
+            mIndices[index_offset++] = pLong[k] /*+ static_cast<unsigned long>(offset)*/;
+        }
+    }
+    else
+    {
+        for ( size_t k = 0; k < numTris*3; ++k)
+        {
+            mIndices[index_offset++] = static_cast<unsigned long>(pShort[k]) /*+
+                                                                             static_cast<unsigned long>(offset)*/;
+        }
+    }
+
+    ibuf->unlock();
+    current_offset = next_offset;
+
+}

File ogre-npr/MeshData.hpp

+#pragma once
+#ifndef __041010_MESHDATA_HPP__
+#define __041010_MESHDATA_HPP__
+
+#include <vector>
+#include <Ogre.h>
+
+class MeshData
+{
+protected:
+    typedef std::vector<Ogre::Vector3> Vertices;
+    typedef std::vector<Ogre::Vector3> Normals;
+    typedef std::vector<unsigned long> Indices;
+
+public:
+    MeshData(Ogre::MeshPtr _mesh
+        , const Ogre::Vector3 &position
+        , const Ogre::Quaternion &orient
+        , const Ogre::Vector3 &scale);
+    ~MeshData();
+
+    Ogre::Vector3 getVertex(unsigned int i){ return mVertices[i];};
+    Ogre::Vector3 getNormal(unsigned int i){ return mNormals[i];};
+    unsigned long getIndex(unsigned int i){ return mIndices[i];};
+
+protected:
+    void _getMeshInformation();
+    void _initBuffers();
+    void _extractBufferSizes(); 
+    void _extractVertexData(Ogre::SubMesh*);
+    void _extractPositions(Ogre::VertexData *_vertexdata);
+    void _extractNormals(Ogre::VertexData *_vertexdata);
+    void _extractIndexBuffer(Ogre::SubMesh*);
+
+protected:
+    Ogre::MeshPtr mMesh;
+    Ogre::Vector3 mPosition;
+    Ogre::Vector3 mScale;
+    Ogre::Quaternion mRotation;
+
+    size_t mVertexCount;
+    Vertices mVertices;
+    Normals mNormals;
+    size_t mIndexCount;
+    Indices mIndices;
+
+    bool added_shared;
+    size_t current_offset;
+    size_t shared_offset;
+    size_t next_offset;
+    size_t index_offset;
+
+
+
+};
+
+#endif 

File ogre-npr/NPRDemoApp.cpp

 {
     if(mKeyboard->isKeyDown(OIS::KC_H))
     {
-        BOOST_FOREACH(EdgeGeometryItem item, mEdges)
-        {
-            mEdgesVisible = !mEdgesVisible;
-            _setEdgesVisible(item, mEdgesVisible);
-        }
+        //BOOST_FOREACH(EdgeGeometryItem item, mEdges)
+        //{
+        //    mEdgesVisible = !mEdgesVisible;
+        //    _setEdgesVisible(item, mEdgesVisible);
+        //}
     }
     return OgreApplication::keyReleased(e);
 }
     //_loadMesh("ulb_building_bat_C_1", Vector3(-1200, 0, 0));
     //_loadMesh("ulb_building_bat_C_2", Vector3(-1200, 0, 0));
 
-    //_loadMesh("ulb_building_ASCENCEUR", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_ASCENCEUR", Vector3(-1200, 0, 0));
 
  
-    //_loadMesh("ulb_building_BAT_NEXT", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_BAT_PRINCIPAL", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_bat_projet broullion", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_bat_S_W", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_batiment_plus", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_BAT_NEXT", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_BAT_PRINCIPAL", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_bat_projet_broullion", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_bat_S_W", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_batiment_plus", Vector3(-1200, 0, 0));
 
 
-    //_loadMesh("ulb_building_BATIMENTS_PROJET", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_BATIMENTS_TOUT", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_Calque1", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_Calque2", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_COURBES", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_BATIMENTS_PROJET", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_BATIMENTS_TOUT", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_Calque1", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_Calque2", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_COURBES", Vector3(-1200, 0, 0));
 
-    //_loadMesh("ulb_building_galleries", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_Layer0", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_galleries", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_Layer0", Vector3(-1200, 0, 0));
 
-    //_loadMesh("ulb_building_Le_Batiment", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_route relief", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_Le_Batiment", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_route_relief", Vector3(-1200, 0, 0));
 
-    //_loadMesh("ulb_building_tour", Vector3(-1200, 0, 0));
-    //_loadMesh("ulb_building_Z_LAYOUT", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_tour", Vector3(-1200, 0, 0));
+    _loadMesh("ulb_building_Z_LAYOUT", Vector3(-1200, 0, 0));
 
     ////node->translate(0, 0, -1500);
     //node->scale(0.1, 0.1, 0.1);
                     ,mSceneMgr,_node, this);
 }
 //-----------------------------------------------------------------------------
-SceneNode* NPRDemoApp::_loadMesh(const String &_name, const Vector3 &_pos)
+SceneNode* NPRDemoApp::_loadMesh(const Ogre::String &_name, const Ogre::Vector3 &_pos)
 {
     Entity *ent = mSceneMgr->createEntity(_name, _name+".mesh");
     SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(_name+"Node", _pos);
 	ent->setMaterialName("Shading/PerPixel/Gooch");
     node->attachObject(ent);
 
-    ManualObject *edges = _createQuadFinGeometry(ent);
+    EdgeGeometryBuilder *edges = new EdgeGeometryBuilder(mLog, mSceneMgr);
+    edges->addEdgesForEntity(ent);
     edges->setVisible(true);
-    node->attachObject(edges);
-    
-
-    mEdges.push_back(EdgeGeometryItem(edges, node));
+    edges->attachToSceneNode(node);
 
     return node;
 }
 //-----------------------------------------------------------------------------
-ManualObject* NPRDemoApp::_createQuadFinGeometry(Ogre::Entity *_ent)
-{
-    mLog->logMessage("Creating edges for entity : " + _ent->getName());
 
-    MeshPtr mesh = _ent->getMesh();
-
-    {
-        boost::format fmt("Mesh has %d submeshes");
-        fmt % mesh->getNumSubMeshes();
-        mLog->logMessage(fmt.str());
-    }
-
-    // we want to generate edges for all submeshes
-    //Mesh::SubMeshIterator submeshIt = mesh->getSubMeshIterator();
-    //while (submeshIt.hasMoreElements())
-    //{
-    //    submeshIt.getNext()->setBuildEdgesEnabled(true);
-    //} 
-
-    mesh->getSubMesh(0)->setBuildEdgesEnabled(true);
-    mesh->getSubMesh(1)->setBuildEdgesEnabled(true);
-
-    mesh->buildEdgeList();
-                     
-    EdgeData *edgeData = mesh->getEdgeList();
-    
-
-    {
-        boost::format fmt("Generating %d edgegroups");
-        fmt % edgeData->edgeGroups.size();
-        mLog->logMessage(fmt.str());
-    }
-
-
-    ManualObject *edgeGeometry = mSceneMgr->createManualObject(_ent->getName() + "edges");
-
-    MeshData meshData;
-    _getMeshInformation(mesh, meshData, Vector3::ZERO, Quaternion::IDENTITY, Vector3(1,1,1));
-
-
-    edgeGeometry->begin("NPR/EdgeOutliner", RenderOperation::OT_TRIANGLE_LIST);
-
-    int idx=0;
-    for(int edgeGroupIdx = 0 ; edgeGroupIdx < edgeData->edgeGroups.size() ; edgeGroupIdx++)
-    {
-        {
-            boost::format fmt("Adding edges for edgegroup[%d]");
-            fmt % edgeGroupIdx ;
-            mLog->logMessage(fmt.str());
-        }
-
-        int edgeCount = edgeData->edgeGroups[edgeGroupIdx].edges.size();
-
-
-        for(int i=0; i<edgeCount ; i++)
-        {
-            EdgeData::Edge e = edgeData->edgeGroups[0].edges[i];
-
-            Vector3 v0, v1;
-            Vector4 nA, nB ;
-            Real markedEdge;
-
-            if(e.degenerate)
-            {
-                v0 =  meshData.vertices[e.vertIndex[0]];
-                v1 =  meshData.vertices[e.vertIndex[1]];
-
-                nA = edgeData->triangleFaceNormals[e.triIndex[0]];
-                nB = -nA;
-                markedEdge = 2.0f;
-            }
-            else
-            {
-                v0 =  meshData.vertices[e.vertIndex[0]];
-                v1 =  meshData.vertices[e.vertIndex[1]];
-
-                nA = edgeData->triangleFaceNormals[e.triIndex[0]];
-                nB = edgeData->triangleFaceNormals[e.triIndex[1]];
-            
-                Real ridgeThreshold = Degree(10.0f).valueRadians();
-                Real valleyThreshold = Degree(10.0f).valueRadians();
-
-
-                bool isRidge = _isEdgeARidge(Vector3(nA.x, nA.y, nA.z)
-                    ,Vector3(nB.x, nB.y, nB.z)
-                    ,ridgeThreshold);
-
-                bool isValley = _isEdgeAValley(Vector3(nA.x, nA.y, nA.z)
-                    ,Vector3(nB.x, nB.y, nB.z)
-                    ,valleyThreshold);
-
-
-                markedEdge = (isRidge || isValley) ? 1.0f : 0.0f;
-            }
-
-            {
-                boost::format fmt("Adding new edge for position : (%.2f, %.2f, %.2f)  (%.2f, %.2f, %.2f)");
-                fmt % v0.x % v0.y % v0.z % v1.x % v1.y % v0.z; 
-                mLog->logMessage(fmt.str());
-            }
-
-            v0 += Vector3(0, edgeGroupIdx*100, 0);
-            v1 += Vector3(0, edgeGroupIdx*100, 0);
-
-            _buildEdgeQuad(v0, v1, nA, nB, markedEdge, idx, edgeGeometry);
-            idx+=6;
-        }
-
-        {
-            boost::format fmt("%s : Added %d edges (%d tris, %d vertices)");
-            fmt % edgeGeometry->getName() % (idx/6) % (idx/3) % (idx);
-            mLog->logMessage(fmt.str());
-        }
-    }
-    edgeGeometry->end();
-    return edgeGeometry;
-}
-//-----------------------------------------------------------------------------
-void NPRDemoApp::_buildEdgeQuad(  const Vector3 &_v0, const Vector3&_v1
-                                   , const Vector4 &_nA,const Vector4&_nB
-                                   , const Real _markedEdge,unsigned int _idx
-                                   , ManualObject *_edgeGeometry)
-{
-    Vector3 nA = Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
-    Vector3 nB = Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
-        
-    /* 1st tri
-       1 __ 2
-        | /
-        |/
-        3
-    */
-    _edgeGeometry->position(_v0);
-    _edgeGeometry->normal(nA);
-    _edgeGeometry->textureCoord(nB);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-
-    _edgeGeometry->position(_v0);
-    _edgeGeometry->normal(nB);
-    _edgeGeometry->textureCoord(nA);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-
-    _edgeGeometry->position(_v1);
-    _edgeGeometry->normal(nA);
-    _edgeGeometry->textureCoord(nB);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-
-    /* 2nd tri
-          6
-         /|
-        /_|
-       4   5
-    */
-    _edgeGeometry->position(_v1);
-    _edgeGeometry->normal(nA);
-    _edgeGeometry->textureCoord(nB);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-
-    _edgeGeometry->position(_v0);
-    _edgeGeometry->normal(nB);
-    _edgeGeometry->textureCoord(nA);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-
-    _edgeGeometry->position(_v1);
-    _edgeGeometry->normal(nB);
-    _edgeGeometry->textureCoord(nA);
-    _edgeGeometry->textureCoord(_markedEdge);
-
-    _edgeGeometry->index(_idx++);
-}
 //-----------------------------------------------------------------------------
 void NPRDemoApp::_setCelShadingMaterial(Entity *_ent)
 {
 #endif
 }
 //-----------------------------------------------------------------------------
-void NPRDemoApp::_getMeshInformation(const MeshPtr              _mesh
-                                    ,NPRDemoApp::MeshData       &_meshData
-                                    ,const Vector3              &_position
-                                    ,const Quaternion           &_orient
-                                    ,const Vector3              &_scale)
-{
-    bool added_shared = false;
-    size_t current_offset = 0;
-    size_t shared_offset = 0;
-    size_t next_offset = 0;
-    size_t index_offset = 0;
 
-    _meshData.vertexCount = _meshData.indexCount = 0;
-
-    // Calculate how many vertices and indices we're going to need
-    for (unsigned short i = 0; i < _mesh->getNumSubMeshes(); ++i)
-    {
-        Ogre::SubMesh* submesh = _mesh->getSubMesh( i );
-
-        // We only need to add the shared vertices once
-        if(submesh->useSharedVertices)
-        {
-            if( !added_shared )
-            {
-                _meshData.vertexCount += _mesh->sharedVertexData->vertexCount;
-                added_shared = true;
-            }
-        }
-        else
-        {
-            _meshData.vertexCount += submesh->vertexData->vertexCount;
-        }
-
-        // Add the indices
-        _meshData.indexCount += submesh->indexData->indexCount;
-    }
-
-
-    // Allocate space for the vertices and indices
-    _meshData.vertices = new Vector3[_meshData.vertexCount];
-    _meshData.normals = new Vector3[_meshData.vertexCount];
-    _meshData.indices = new unsigned long[_meshData.indexCount];
-
-    
-
-    added_shared = false;
-
-    // Run through the submeshes again, adding the data into the arrays
-    for ( unsigned short i = 0; i < _mesh->getNumSubMeshes(); ++i)
-    {
-        Ogre::SubMesh* submesh = _mesh->getSubMesh(i);
-
-        Ogre::VertexData* vertex_data = submesh->useSharedVertices ? _mesh->sharedVertexData : submesh->vertexData;
-
-        if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
-        {
-            if(submesh->useSharedVertices)
-            {
-                added_shared = true;
-                shared_offset = current_offset;
-            }
-    
-            // get position
-            {
-                const Ogre::VertexElement* posElem =
-                    vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
-                
-                Ogre::HardwareVertexBufferSharedPtr vbuf =
-                    vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
-
-                unsigned char* vertex =
-                    static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
-
-                // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double
-                //  as second argument. So make it float, to avoid trouble when Ogre::Real will
-                //  be comiled/typedefed as double:
-                //      Ogre::Real* pReal;
-                float* pReal;
-
-                for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
-                {
-                    posElem->baseVertexPointerToElement(vertex, &pReal);
-
-                    Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]);
-
-                    _meshData.vertices[current_offset + j] = (_orient * (pt * _scale)) + _position;
-                }
-                vbuf->unlock();
-            }
-            // get normals
-            {
-                const Ogre::VertexElement* normalElem =
-                    vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_NORMAL);
-                
-                Ogre::HardwareVertexBufferSharedPtr vbuf =
-                    vertex_data->vertexBufferBinding->getBuffer(normalElem->getSource());
-
-                unsigned char* normal =
-                    static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
-
-                float* pReal;
-                for( size_t j = 0; j < vertex_data->vertexCount; ++j, normal += vbuf->getVertexSize())
-                {
-                    normalElem->baseVertexPointerToElement(normal, &pReal);
-
-                    Ogre::Vector3 normal(pReal[0], pReal[1], pReal[2]);
-
-                    _meshData.normals[current_offset + j] = (_orient * (normal));
-                }
-                vbuf->unlock();
-            }
-
-
-
-            next_offset += vertex_data->vertexCount;
-        }
-
-
-        Ogre::IndexData* index_data = submesh->indexData;
-        size_t numTris = index_data->indexCount / 3;
-        Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
-
-        bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
-
-        unsigned long*  pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
-        unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong);
-
-
-        size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset;
-
-        // Ogre 1.6 patch (commenting the static_cast...) - index offsets start from 0 for each submesh
-        if ( use32bitindexes )
-        {
-            for ( size_t k = 0; k < numTris*3; ++k)
-            {
-                _meshData.indices[index_offset++] = pLong[k] /*+ static_cast<unsigned long>(offset)*/;
-            }
-        }
-        else
-        {
-            for ( size_t k = 0; k < numTris*3; ++k)
-            {
-                _meshData.indices[index_offset++] = static_cast<unsigned long>(pShort[k]) /*+
-                                                                                static_cast<unsigned long>(offset)*/;
-            }
-        }
-
-        ibuf->unlock();
-        current_offset = next_offset;
-    }
-} 
-//-----------------------------------------------------------------------------
-bool NPRDemoApp::_isEdgeARidge(const Vector3 &_nA, const Vector3 &_nB, const Real &_threshold)
-{
-    Vector3 nA_norm = Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
-    Vector3 nB_norm = Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
-
-    return nA_norm.dotProduct(nB_norm) < Math::Cos(_threshold);
-}
-//-----------------------------------------------------------------------------
-bool NPRDemoApp::_isEdgeAValley(const Vector3 &_nA, const Vector3 &_nB, const Real &_threshold)
-{
-    Vector3 nA_norm = Vector3(_nA.x, _nA.y, _nA.z).normalisedCopy();
-    Vector3 nB_norm = Vector3(_nB.x, _nB.y, _nB.z).normalisedCopy();
-
-    return nA_norm.dotProduct(nB_norm) < Math::Cos(_threshold);
-}
-//-----------------------------------------------------------------------------
-void NPRDemoApp::CreatedEntity(const OgreMax::OgreMaxScene* scene
-                                 ,Ogre::Entity* entity)
-{
-    entity->setMaterialName("NPR/Face");
-    ManualObject *edges = _createQuadFinGeometry(entity);
-    edges->setVisible(true);
-
-    SceneNode *node = entity->getParentSceneNode();
-
-    if (node)
-    {
-        node->attachObject(edges);
-        node->setVisible(true); 
-    }
-}
-//-----------------------------------------------------------------------------
-void NPRDemoApp::_setEdgesVisible(EdgeGeometryItem &_item, bool _visible)
-{
-    ManualObject *edges = _item.first;
-    SceneNode    *node  = _item.second;
-    
-    node->setVisible(_visible);
-    edges->setVisible(_visible);
-}
-//-----------------------------------------------------------------------------
+////-----------------------------------------------------------------------------
+//void NPRDemoApp::CreatedEntity(const OgreMax::OgreMaxScene* scene
+//                                 ,Ogre::Entity* entity)
+//{
+//    entity->setMaterialName("NPR/Face");
+//    ManualObject *edges = _createQuadFinGeometry(entity);
+//    edges->setVisible(true);
+//
+//    SceneNode *node = entity->getParentSceneNode();
+//
+//    if (node)
+//    {
+//        node->attachObject(edges);
+//        node->setVisible(true); 
+//    }
+//}
+////-----------------------------------------------------------------------------
+//void NPRDemoApp::_setEdgesVisible(EdgeGeometryItem &_item, bool _visible)
+//{
+//    ManualObject *edges = _item.first;
+//    SceneNode    *node  = _item.second;
+//    
+//    node->setVisible(_visible);
+//    edges->setVisible(_visible);
+//}
+////-----------------------------------------------------------------------------

File ogre-npr/NPRDemoApp.h

 #include "OgreApplication.h"
 #include "TextRenderer.h"
 
+#include "EdgeGeometryBuilder.hpp"
 #include <OgreMaxScene.hpp>
 
-using namespace Ogre;
-
-
 class NPRDemoApp : public OgreApplication, public OgreMax::OgreMaxSceneCallback
 {
-protected:
-    typedef struct 
-    {
-        size_t          vertexCount;
-        Vector3         *vertices;
-        Vector3         *normals;
-        size_t          indexCount;
-        unsigned long   *indices;
-    }MeshData;
-
-    typedef std::pair<ManualObject*, SceneNode*>    EdgeGeometryItem;
-    typedef std::list<EdgeGeometryItem>             EdgeGeometryList;
-
-
 public:
     NPRDemoApp();
     void createScene();
-    ManualObject*   _createQuadFinGeometry(Entity*);
+    Ogre::ManualObject*   _createQuadFinGeometry(Entity*);
 
     bool frameStarted(const FrameEvent& evt);
     bool keyReleased( const OIS::KeyEvent &e );
     SceneNode*      _loadMesh(const String&, const Vector3&);
     void            _setCelShadingMaterial(Entity*);
 
-    void            _getMeshInformation(const MeshPtr mesh,
-                                        MeshData &meshData,
-                                        const Vector3 &position,
-                                        const Quaternion &orient,
-                                        const Vector3 &scale);
 
     void _loadScene(const String&, SceneNode*);
 
-    void _buildEdgeQuad(const Vector3&, const Vector3&
-                        , const Vector4&,const Vector4&
-                        , const Real, unsigned int
-                        , ManualObject*);
 
-    inline bool _isEdgeARidge(const Vector3&, const Vector3&, const Real&);
-    inline bool _isEdgeAValley(const Vector3&, const Vector3&, const Real&);
 
     // overlay
     void _createDebugOverlay();
     void _updateDebugOverlay();
 
     // OgreMaxSceneCallback
-    void CreatedEntity(const OgreMax::OgreMaxScene*, Ogre::Entity*);
+    void CreatedEntity(const OgreMax::OgreMaxScene*, Ogre::Entity*){};
 
-    void _setEdgesVisible(EdgeGeometryItem&, bool);
+    //void _setEdgesVisible(EdgeGeometryItem&, bool);
 
 protected:
     BillboardSet *mBBset;
     TextRenderer *mDebugText;
 
     AnimationState *mAnimState;
-    EdgeGeometryList mEdges;
+    //EdgeGeometryList mEdges;
     bool mEdgesVisible;
 
     Log *mLog;
+    std::list<EdgeGeometryBuilder*> mEdges;
 };
 
 

File ogre-npr/ogre-npr.vcproj

 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
+				RelativePath=".\EdgeGeometryBuilder.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\MeshData.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\NPRDemoApp.cpp"
 				>
 			</File>
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
 			<File
+				RelativePath=".\EdgeGeometryBuilder.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\MeshData.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\NPRDemoApp.h"
 				>
 			</File>