source: GTP/trunk/Lib/Illum/IBRBillboardCloudTrees/OGRE/src/BBCOgreMeshSerializer.cpp @ 699

Revision 699, 10.8 KB checked in by igarcia, 19 years ago (diff)
Line 
1#include "BBCOgreMeshSerializer.h"
2
3namespace BBC {
4
5    UniqueVertex::UniqueVertex()
6        : position(Ogre::Vector3::ZERO), normal(Ogre::Vector3::ZERO), colour(0), nextIndex(0)
7    {
8        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i)
9            uv[i] = Ogre::Vector3::ZERO;
10    }
11
12    bool UniqueVertex::operator==(const UniqueVertex& rhs) const
13    {
14        bool ret = position == rhs.position &&
15            normal == rhs.normal &&
16            colour == rhs.colour;
17        if (!ret) return ret;
18
19        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS && ret; ++i)
20        {
21            ret = ret && (uv[i] == rhs.uv[i]);
22        }
23
24        return ret;
25    }
26
27        void OgreMeshSerializer::setEntity(Entity *entity)
28        {
29                mEntity = entity;
30        }
31
32        Entity* OgreMeshSerializer::getEntity()
33        {
34                return mEntity;
35        }
36
37    OgreMeshSerializer::OgreMeshSerializer()
38    {
39    }
40
41    OgreMeshSerializer::~OgreMeshSerializer()
42    {
43    }
44
45
46        void OgreMeshSerializer::exportMesh(const Ogre::String& fileName, bool mergeSubMeshes = false, bool tangents = false)
47    {
48
49                Ogre::LogManager::getSingleton().logMessage("** Begin OGRE Mesh Export **");
50        // Derive the scene root
51
52        // Construct mesh
53        Ogre::MeshPtr pMesh = Ogre::MeshManager::getSingleton().createManual(fileName,
54                        Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
55
56                mEntity->setMesh(pMesh.getPointer());
57
58                // write the data into a mesh
59                buildMesh(pMesh.getPointer(), mergeSubMeshes);
60
61        if(tangents)
62        {
63            Ogre::LogManager::getSingleton().logMessage("Calculating tangents");
64            unsigned short src, dest;
65            if (pMesh->suggestTangentVectorBuildParams(src, dest))
66            {
67                pMesh->buildTangentVectors(src, dest);
68            }
69            else
70            {
71                Ogre::LogManager::getSingleton().logMessage("Could not derive tangents parameters");
72            }
73        }
74
75                Ogre::LogManager::getSingleton().logMessage("** OGRE Mesh Export Complete **");
76    }
77 
78        void OgreMeshSerializer::buildMesh(Ogre::Mesh* pMesh, bool mergeSubmeshes)
79        {
80                if (!mergeSubmeshes)
81                {
82                        // build contents of this polymesh into ProtoSubMesh(es)
83                        generateEntityAABB(pMesh);
84                       
85                        // export out at the end of every PolygonMesh
86                        exportSubMeshes(pMesh);
87                }
88                // TODO
89                if (mergeSubmeshes)
90                {
91                        // build contents of this polymesh into ProtoSubMesh(es)
92                        mEntity->mergeSubEntities();
93
94                        generateEntityAABB(pMesh);
95
96                        // export out the combined result
97                        exportSubMeshes(pMesh);
98                }               
99        }
100 
101        void OgreMeshSerializer::generateEntityAABB(Ogre::Mesh* pMesh)
102        {
103                // Bounds calculation
104                Ogre::Real squaredRadius = 0.0f;
105        Ogre::Vector3 min, max;
106        bool first = true;
107               
108                for (unsigned int iSubEntity = 0; iSubEntity < mEntity->getNumSubEntities(); iSubEntity++)
109                {
110                        for (size_t jVertex = 0; jVertex < mEntity->getSubEntity(iSubEntity)->getNumVertices(); jVertex++)
111                        {
112                                if (first)
113                                {
114                                        squaredRadius = mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position.squaredLength();
115                                        min = max = mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position;
116                                        first = false;
117                                }
118                                else
119                                {
120                                        size_t numVertices = (unsigned int)mEntity->getSubEntity(iSubEntity)->getNumVertices();
121                                        //Ogre::LogManager::getSingleton().logMessage("NumVertices:" + Ogre::StringConverter::toString(numVertices));
122                                        //Ogre::LogManager::getSingleton().logMessage("IDVertex:" + Ogre::StringConverter::toString(jVertex) + "--" + Ogre::StringConverter::toString(iSubEntity) + "--" + Ogre::StringConverter::toString(mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position));
123                                        squaredRadius =
124                                                std::max(squaredRadius,mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position.squaredLength());
125                                        min.makeFloor(mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position);
126                                        max.makeCeil(mEntity->getSubEntity(iSubEntity)->getUniqueVertex(jVertex).position);
127                                }
128                        }
129        }
130
131                // Merge bounds
132                Ogre::AxisAlignedBox box;
133        box.setExtents(min, max);
134        box.merge(pMesh->getBounds());
135        pMesh->_setBounds(box);
136        pMesh->_setBoundingSphereRadius(
137                        std::max(
138                                pMesh->getBoundingSphereRadius(),
139                                Ogre::Math::Sqrt(squaredRadius)));     
140
141                Ogre::LogManager::getSingleton().logMessage("Bounds:" + Ogre::StringConverter::toString(pMesh->getBoundingSphereRadius()) + " -- Generated:" + Ogre::StringConverter::toString(pMesh->getBounds().isNull()));
142        }
143 
144        void OgreMeshSerializer::exportSubMeshes(Ogre::Mesh* pMesh)
145        {
146                for (unsigned int iSubEntity = 0; iSubEntity < mEntity->getNumSubEntities(); iSubEntity++)
147                {
148                        exportSubMesh(pMesh,mEntity->getSubEntity(iSubEntity));
149                }               
150        }
151 
152        void OgreMeshSerializer::exportSubMesh(Ogre::Mesh* pMesh, SubEntity *subEntity)
153        {               
154        Ogre::SubMesh* sm = 0;
155        if (subEntity->getName() == "")
156        {
157            sm = pMesh->createSubMesh();
158        }
159        else
160        {
161            sm = pMesh->createSubMesh(subEntity->getName());
162        }
163        // Set material
164        sm->setMaterialName(subEntity->getMaterialName());
165        // never use shared geometry
166        sm->useSharedVertices = false;
167                sm->vertexData = new Ogre::VertexData();
168        // always do triangle list
169        sm->indexData->indexCount = subEntity->getNumFaces()*3;
170               
171                sm->vertexData->vertexCount = subEntity->getNumVertices();
172        // Determine index size
173        bool use32BitIndexes = false;
174        if (subEntity->getNumVertices() > 65536)
175        {
176            use32BitIndexes = true;
177        }
178
179        sm->indexData->indexBuffer =
180            Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
181            use32BitIndexes ? Ogre::HardwareIndexBuffer::IT_32BIT : Ogre::HardwareIndexBuffer::IT_16BIT,
182            sm->indexData->indexCount,
183            Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
184
185        if (use32BitIndexes)
186        {
187            unsigned int* pIdx = static_cast<unsigned int*>(
188                sm->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
189                writeIndexes(pIdx,subEntity);
190                sm->indexData->indexBuffer->unlock();
191        }
192        else
193        {
194            unsigned short int* pIdx = static_cast<unsigned short int*>(
195                sm->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
196                                writeIndexes(pIdx,subEntity);
197                                sm->indexData->indexBuffer->unlock();
198        }
199               
200               
201        // define vertex declaration
202        unsigned buf = 0;
203        size_t offset = 0;
204                // always add position and normal
205        sm->vertexData->vertexDeclaration->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
206                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
207        sm->vertexData->vertexDeclaration->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
208                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
209
210                // Optional vertex colour
211        if(subEntity->hasVertexColours())
212        {
213            sm->vertexData->vertexDeclaration->addElement(buf, offset, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
214                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR);
215        }
216
217        // Define UVs
218        for (unsigned short uvi = 0; uvi < subEntity->getNumTexCoordSets(); uvi++)
219        {
220                        Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, subEntity->getTexCoordDimensions(uvi));
221            sm->vertexData->vertexDeclaration->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, uvi);
222                        offset += Ogre::VertexElement::getTypeSize(uvType);
223        }
224
225        // create & fill buffer(s)
226        for (unsigned short b = 0; b <= sm->vertexData->vertexDeclaration->getMaxSource(); ++b)
227        {
228            createVertexBuffer(sm->vertexData, b, subEntity->getUniqueVertices());
229        }
230        }
231 
232    template <typename T>
233    void OgreMeshSerializer::writeIndexes(T* buf, SubEntity *subEntity)
234    {
235        for (unsigned int i = 0;  i < subEntity->getNumFaces(); i++)
236        {                       
237                        Ogre::Vector3 indexes = subEntity->getFaceVerticesIDs(i);
238                        unsigned int i0, i1, i2;
239                        i0 = (unsigned int)indexes[0];
240                        i1 = (unsigned int)indexes[1];
241                        i2 = (unsigned int)indexes[2];
242            *buf++ = static_cast<T>(i0);
243                        *buf++ = static_cast<T>(i1);
244                        *buf++ = static_cast<T>(i2);
245        }
246    }
247
248        void OgreMeshSerializer::createVertexBuffer(Ogre::VertexData* vd,
249                unsigned short bufIdx, UniqueVertexList *uniqueVertexList)
250    {
251                Ogre::HardwareVertexBufferSharedPtr vbuf =
252                        Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
253                vd->vertexDeclaration->getVertexSize(bufIdx),
254                vd->vertexCount,
255                Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
256        vd->vertexBufferBinding->setBinding(bufIdx, vbuf);
257        size_t vertexSize = vd->vertexDeclaration->getVertexSize(bufIdx);
258
259        char* pBase = static_cast<char*>(
260                                vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
261
262                Ogre::VertexDeclaration::VertexElementList elems =
263                        vd->vertexDeclaration->findElementsBySource(bufIdx);
264                Ogre::VertexDeclaration::VertexElementList::iterator ei, eiend;
265        eiend = elems.end();
266        float* pFloat;
267        Ogre::RGBA* pRGBA;
268
269        UniqueVertexList::iterator srci = uniqueVertexList->begin();
270
271        for (size_t v = 0; v < vd->vertexCount; ++v, ++srci)
272        {
273            for (ei = elems.begin(); ei != eiend; ++ei)
274            {
275                                Ogre::VertexElement& elem = *ei;
276                switch(elem.getSemantic())
277                {
278                case Ogre::VES_POSITION:
279                    elem.baseVertexPointerToElement(pBase, &pFloat);
280                    *pFloat++ = srci->position.x;
281                    *pFloat++ = srci->position.y;
282                    *pFloat++ = srci->position.z;
283                    break;
284                case Ogre::VES_NORMAL:
285                    elem.baseVertexPointerToElement(pBase, &pFloat);
286                    *pFloat++ = srci->normal.x;
287                    *pFloat++ = srci->normal.y;
288                    *pFloat++ = srci->normal.z;
289                    break;
290                case Ogre::VES_DIFFUSE:
291                    elem.baseVertexPointerToElement(pBase, &pRGBA);
292                    *pRGBA = srci->colour;
293                    break;
294                case Ogre::VES_TEXTURE_COORDINATES:
295                    elem.baseVertexPointerToElement(pBase, &pFloat);
296                                        for (int t = 0; t < Ogre::VertexElement::getTypeCount(elem.getType()); ++t)
297                                        {
298                                                Ogre::Real val = srci->uv[elem.getIndex()][t];
299                                                *pFloat++ = val;
300                                        }
301                    break;
302                }
303            }
304            pBase += vertexSize;
305        }
306        vbuf->unlock();
307
308    }
309
310}
Note: See TracBrowser for help on using the repository browser.