Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ColladaPlugin/src/OgreColladaGeometry.cpp @ 21

Last change on this file since 21 was 21, checked in by nicolasc, 17 years ago

added ogreode and Colladaplugin

File size: 31.7 KB
RevLine 
[21]1/**
2 * This source file is part of OgreColladaPlugin
3 * an addon for OGRE (Object-oriented Graphics Rendering Engine)
4 * For the latest info, see http://www.ogre3d.org/
5 *
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by the Free Software
8 * Foundation; either version 2 of the License, or (at your option) any later
9 * version.
10
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14
15 * You should have received a copy of the GNU Lesser General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
18 * http://www.gnu.org/copyleft/lesser.txt.
19 *
20 * @author      Philipp Hartl
21 * @see         README
22 */
23
24#include "OgreColladaGeometry.h"
25#include "OgreColladaDocument.h"
26#include "OgreColladaLibrary.h"
27#include "OgreColladaMaterial.h"
28#include "OgreColladaScene.h"
29#include "OgreColladaSyntax.h"
30#include "OgreColladaUtils.h"
31
32#include "OgreSceneManager.h"
33#include "OgreMovableObject.h"
34#include "OgreMeshManager.h"
35#include "OgreSubMesh.h"
36#include "OgreEntity.h"
37#include "OgreStringConverter.h"
38
39namespace Ogre
40{
41        //-------------------------------------------------------------------------
42        ColladaGeometry::ColladaGeometry(ColladaDocument *doc, xmlNode *n) : ColladaEntity(doc, n)
43        { 
44                mOgreMesh = NULL;
45                mEntityName = "";
46                mBB = NULL;
47                mBBReset = false;
48        }
49
50        //-------------------------------------------------------------------------
51        ColladaGeometry::~ColladaGeometry(void) 
52        {
53                if (!mSources.empty())
54                {
55                        for (ColladaGeometrySourcePtrVector::iterator i = mSources.begin(); i != mSources.end(); ++i)
56                        {
57                                (*i)->data.clear();
58                                OGRE_DELETE(*i);
59                        }
60                        mSources.clear();
61                }
62                if (!mVertexInputs.empty())
63                {
64                        for (ColladaGeometryInputDataPtrVector::iterator i = mVertexInputs.begin(); i != mVertexInputs.end(); ++i)
65                        {
66                                // source already freed
67                                OGRE_DELETE(*i);
68                        }
69                        mVertexInputs.clear();
70                }
71                if (!mPolygons.empty())
72                {
73                        for (ColladaGeometryPolygonPtrVector::iterator i = mPolygons.begin(); i != mPolygons.end(); ++i)
74                        {
75                                for (ColladaGeometryInputDataPtrVector::iterator j = (*i)->inputs.begin(); j != (*i)->inputs.end(); ++j)
76                                {
77                                        // source already freed
78                                        OGRE_DELETE(*j);
79                                }
80                                (*i)->inputs.clear();
81                                (*i)->material = NULL;
82                                OGRE_DELETE(*i);       
83                        }
84                        mPolygons.clear();
85                }
86
87                if (mOgreMesh != NULL)
88                {
89                        for (ColladaGeometryOgreMeshIndexData::iterator it = mOgreMesh->indices.begin(); it != mOgreMesh->indices.end(); ++it)
90                        {
91                                OGRE_DELETE_ARRAY((*it)->indices);
92                                OGRE_DELETE(*it);
93                        }
94                        mOgreMesh->indices.clear();
95                        OGRE_DELETE_ARRAY(mOgreMesh->vertices);
96                        OGRE_DELETE(mOgreMesh);
97                }
98
99                if (mBBReset) mBB = NULL;
100                else OGRE_DELETE(mBB); 
101        }
102
103        //-------------------------------------------------------------------------
104        void ColladaGeometry::calcBoundingBox(void)
105        {
106                if (!mBB)
107                {
108                        // calculate a bounding box
109                        ColladaGeometrySource *src = mVertexInputs.at(0)->source;
110
111                        float minX, minY, minZ, maxX, maxY, maxZ;
112                        minX = maxX = src->data.at(0);
113                        minY = maxY = src->data.at(1);
114                        minZ = maxZ = src->data.at(2);
115
116                        for (uint i = 0; i < src->count; i++)
117                        {
118                                uint index = i * 3;
119
120                                if (minX > src->data.at(index)) minX = src->data.at(index);
121                                if (minY > src->data.at(index + 1)) minY = src->data.at(index + 1);
122                                if (minZ > src->data.at(index + 2)) minZ = src->data.at(index + 2);
123
124                                if (maxX < src->data.at(index)) maxX = src->data.at(index);
125                                if (maxY < src->data.at(index + 1)) maxY = src->data.at(index + 1);
126                                if (maxZ < src->data.at(index + 2)) maxZ = src->data.at(index + 2);
127                        }
128
129                        mBB = new ColladaBoundingBox(Vector3(minX, minY, minZ), Vector3(maxX, maxY, maxZ));                     
130                }
131        }
132
133        //-------------------------------------------------------------------------
134        void ColladaGeometry::createTriangleList(void)
135        {
136                // walk through all polygons, there must be at least one at index 0
137                uint polygonCount = static_cast<uint>(mPolygons.size());
138                ColladaGeometryPolygon *polygon = mPolygons.at(0);
139                if (polygon == NULL) return;
140
141                // for simple life
142                ColladaGeometryInputData *vertexInput   = NULL;
143                ColladaGeometryInputData *normalInput   = NULL;
144                ColladaGeometryInputData *texcoordInput = NULL;
145
146                // get all trivial sources through vertex inputs, one index array for all
147                ColladaGeometryInputDataPtrVector::iterator it;
148                for (it = mVertexInputs.begin(); it != mVertexInputs.end(); ++it)
149                {
150                        if ((*it)->semantic == ColladaGeometrySpecific::POSITION) vertexInput = *it;
151                        if ((*it)->semantic == ColladaGeometrySpecific::NORMAL) normalInput = *it;
152                        if ((*it)->semantic == ColladaGeometrySpecific::TEXCOORD) texcoordInput = *it;
153                }
154
155                // look for detailed normals and texcoords, each source with its own index data
156                for (it = polygon->inputs.begin(); it != polygon->inputs.end(); ++it)
157                {
158                        if ((*it)->semantic == ColladaGeometrySpecific::NORMAL) normalInput = *it;
159                        if ((*it)->semantic == ColladaGeometrySpecific::TEXCOORD) texcoordInput = *it;
160                }
161               
162                // vertex, normal, texcoord source counts
163                uint vertexcount = static_cast<uint>(vertexInput->source->data.size());
164                uint normalcount = 0;
165                uint texcoordcount = 0;
166                if (normalInput != NULL) normalcount = static_cast<uint>(normalInput->source->data.size());
167                if (texcoordInput != NULL) texcoordcount = static_cast<uint>(texcoordInput->source->data.size());
168
169                // create new ogre mesh structure
170                mOgreMesh = new ColladaGeometryOgreMesh();
171                mOgreMesh->drawNormals = ((normalInput != NULL) && (normalcount > 0));
172                // are there more normals per vertex?
173                bool normalsEx = (mOgreMesh->drawNormals && (normalcount != vertexcount));
174                mOgreMesh->drawTexCoords = ((texcoordInput != NULL) && (texcoordcount > 0));
175                // more texcoords per vertex
176                bool texcoordsEx = (mOgreMesh->drawTexCoords && (texcoordcount != vertexcount));
177
178                // calc stride size for vertex array
179                uint stridesize = vertexInput->source->stride;
180                if (mOgreMesh->drawNormals) stridesize += normalInput->source->stride;
181                if (mOgreMesh->drawTexCoords) stridesize += texcoordInput->source->stride;
182
183                // how many triangles are in one polygon?
184                // if there are more than one polygon per geometry, the amount should not change!
185                uint trianglesppolygon = 1;
186                uint i = 0;
187                for (i = polygon->vertexCount; i > 3; i--) trianglesppolygon++;
188               
189                /** simple case, each vertex has at maximum only one normal and/or one texture information
190                 * (vertexcount == normalcount == texcoordcount, all data have the same indices)
191                 * so we only have to triangulate the polygon primitive
192                 */
193                if (!normalsEx && !texcoordsEx)
194                {
195                        // create space for the vertex array
196                        mOgreMesh->vertexCount = vertexInput->source->count;
197                        mOgreMesh->vertices = new float[mOgreMesh->vertexCount * stridesize];
198
199                        // (1) fill up vertices with vertex (normal, texcoord) data
200                        // the mesh could be created anyway if polygonCount > 0
201                        uint offset = 0;
202                        for (i = 0; i < mOgreMesh->vertexCount; i++)
203                        {
204                                mOgreMesh->vertices[i * stridesize]             = vertexInput->source->data[i * 3];
205                                mOgreMesh->vertices[i * stridesize + 1] = vertexInput->source->data[i * 3 + 1];
206                                mOgreMesh->vertices[i * stridesize + 2] = vertexInput->source->data[i * 3 + 2];
207                mDoc->correctAxis(&mOgreMesh->vertices[i * stridesize]);
208
209                                offset = 3;
210                                if (mOgreMesh->drawNormals)
211                                {
212                                        mOgreMesh->vertices[i * stridesize + offset]            = normalInput->source->data[i * 3];
213                                        mOgreMesh->vertices[i * stridesize + offset + 1]        = normalInput->source->data[i * 3 + 1];
214                                        mOgreMesh->vertices[i * stridesize + offset + 2]        = normalInput->source->data[i * 3 + 2];
215                    mDoc->correctAxis(&mOgreMesh->vertices[i * stridesize + offset]);
216                                        offset += 3;
217                                }
218
219                                if (mOgreMesh->drawTexCoords)
220                                {
221                                        mOgreMesh->vertices[i * stridesize + offset]            = texcoordInput->source->data[i * 2];
222                                        mOgreMesh->vertices[i * stridesize + offset + 1]        = texcoordInput->source->data[i * 2 + 1];
223                                }
224                        }
225
226                        // (2) fill up indices array for each polygon primitive
227                        for (ColladaGeometryPolygonPtrVector::iterator it = mPolygons.begin(); it != mPolygons.end(); ++it)
228                        {
229                                polygon = *it;
230
231                                // create enough space for the index array
232                                ColladaGeometryIndexData *tmpIndices = new ColladaGeometryIndexData();
233                                tmpIndices->count = trianglesppolygon * polygon->primitiveCount * 3;
234                                tmpIndices->indices = new unsigned short[tmpIndices->count];
235                                tmpIndices->material = ((*it)->setMaterial) ? (*it)->material->getId() : "";
236
237                                // set vertexInput pointer at indices
238                                vertexInput = polygon->inputs.at(0);
239
240                                offset = trianglesppolygon * 3;
241                                uint index = 0;
242                                for (i = 0; i < polygon->primitiveCount; i++)
243                                {
244                                        index = offset * i;
245
246                                        // first triangle
247                                        tmpIndices->indices[index]              = vertexInput->indices[i * polygon->vertexCount];
248                                        tmpIndices->indices[index + 1]  = vertexInput->indices[i * polygon->vertexCount + 1];
249                                        tmpIndices->indices[index + 2]  = vertexInput->indices[i * polygon->vertexCount + 2];
250
251                                        // are there more than one triangle in one primitive?
252                                        for (uint j = 1; j < trianglesppolygon; j++)
253                                        {
254                                                tmpIndices->indices[index + j * 3]         = vertexInput->indices[i * polygon->vertexCount];
255                                                tmpIndices->indices[index + j * 3 + 1] = vertexInput->indices[i * polygon->vertexCount + j + 1];
256                                                tmpIndices->indices[index + j * 3 + 2] = vertexInput->indices[i * polygon->vertexCount + j + 2];
257                                        }
258                                }
259
260                                // save index array
261                                mOgreMesh->indices.push_back(tmpIndices);
262                        }
263                }
264                /** tricky case, each vertex can have more than one normal and/or texture
265                 * normals or texcoord arrays with different indices
266                 */
267                else
268                {
269                        // space for vertex count
270                        mOgreMesh->vertexCount = 0;
271                        ColladaGeometryPolygonPtrVector::iterator it;
272                        for (it = mPolygons.begin(); it != mPolygons.end(); ++it)
273                        {
274                                // the vertexCount should not change!
275                                mOgreMesh->vertexCount += (*it)->primitiveCount * (*it)->vertexCount;
276                        }
277                        mOgreMesh->vertices = new float[mOgreMesh->vertexCount * stridesize];
278
279                        for (it = mPolygons.begin(); it != mPolygons.end(); ++it)
280                        {
281                                polygon = (*it);
282                               
283                                // create enough space for the index array
284                                ColladaGeometryIndexData *tmpIndices = new ColladaGeometryIndexData();
285                                tmpIndices->count = trianglesppolygon * polygon->primitiveCount * 3;
286                                tmpIndices->indices = new unsigned short[tmpIndices->count];
287                                tmpIndices->material = ((*it)->setMaterial) ? (*it)->material->getId() : "";
288
289                                // get vertex indices
290                                intVector *vertexIndices = &polygon->inputs.at(0)->indices;
291
292                                // get normal indices
293                                intVector *normalIndices = &normalInput->indices;
294                                if (!normalsEx) normalIndices = vertexIndices;
295
296                                // get texture indices
297                                intVector *textureIndices = &texcoordInput->indices;
298                                if (!texcoordsEx) textureIndices = vertexIndices;
299
300                                // fill up mVertices and mIndices array in one pass
301                                for (i = 0; i < polygon->primitiveCount; i++)
302                                {
303                                        // starting index for one primitive
304                                        uint pindex = i * polygon->vertexCount;
305
306                                        // (1) vertices
307                                        uint j;
308                                        for (j = 0; j < polygon->vertexCount; j++)
309                                        {
310                                                uint vindex = pindex + j;       // vertex index
311
312                                                // vertex data
313                                                mOgreMesh->vertices[vindex * stridesize]     = vertexInput->source->data[vertexIndices->at(vindex) * 3];
314                                                mOgreMesh->vertices[vindex * stridesize + 1] = vertexInput->source->data[vertexIndices->at(vindex) * 3 + 1];
315                                                mOgreMesh->vertices[vindex * stridesize + 2] = vertexInput->source->data[vertexIndices->at(vindex) * 3 + 2];
316                        mDoc->correctAxis(&mOgreMesh->vertices[vindex * stridesize]);
317
318                                                uint offset = 3;
319                                                if (mOgreMesh->drawNormals)
320                                                {
321                                                        mOgreMesh->vertices[vindex * stridesize + offset]     = normalInput->source->data[normalIndices->at(vindex) * 3];
322                                                        mOgreMesh->vertices[vindex * stridesize + offset + 1] = normalInput->source->data[normalIndices->at(vindex) * 3 + 1];
323                                                        mOgreMesh->vertices[vindex * stridesize + offset + 2] = normalInput->source->data[normalIndices->at(vindex) * 3 + 2];
324                            mDoc->correctAxis(&mOgreMesh->vertices[vindex * stridesize + offset]);
325
326                                                        offset += 3;
327                                                }
328
329                                                if (mOgreMesh->drawTexCoords)
330                                                {
331                                                        mOgreMesh->vertices[vindex * stridesize + offset]     = texcoordInput->source->data[textureIndices->at(vindex) * 2];
332                                                        mOgreMesh->vertices[vindex * stridesize + offset + 1] = texcoordInput->source->data[textureIndices->at(vindex) * 2 + 1];
333                                                }
334                                        }
335
336                                        // (2) indices
337                                        uint iindex = i * trianglesppolygon * 3;        // indices index
338
339                                        // first triangle
340                                        tmpIndices->indices[iindex]             = pindex;
341                                        tmpIndices->indices[iindex + 1] = pindex + 1;
342                                        tmpIndices->indices[iindex + 2] = pindex + 2;
343
344                                        // are there more than one triangle in one primitive?
345                                        for (j = 1; j < trianglesppolygon; j++)
346                                        {
347                                                tmpIndices->indices[iindex + j * 3]     = pindex;
348                                                tmpIndices->indices[iindex + j * 3 + 1] = pindex + j + 1;
349                                                tmpIndices->indices[iindex + j * 3 + 2] = pindex + j + 2;
350                                        }
351                                }
352
353                                // save index array
354                                mOgreMesh->indices.push_back(tmpIndices);
355                        }
356                }
357
358                // TEST
359                // printVertices(stridesize);
360                // printIndices();
361        }
362
363        //-------------------------------------------------------------------------
364        MovableObject *ColladaGeometry::getOgreInstance(void) const
365        {
366                if (mOgreMesh != NULL && !mEntityName.empty())
367                {
368                        // create hw-buffers and push the data there, material will be set too
369                        createOgreMesh();
370
371                        return mDoc->getSceneManager()->createEntity(mEntityName, mId);
372                }
373
374                return NULL;
375        }
376
377        //-------------------------------------------------------------------------
378        void ColladaGeometry::createOgreMesh(void) const
379        {
380                //if (MeshManager::getSingleton().getByName(mId) != static_cast<ResourcePtr>(NULL)) return;
381                ResourcePtr p;
382                if (MeshManager::getSingleton().getByName(mId) != p)
383                        return;
384
385                MeshPtr pMesh = MeshManager::getSingleton().createManual(mId, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
386                pMesh->sharedVertexData = new VertexData();
387                pMesh->sharedVertexData->vertexCount = mOgreMesh->vertexCount;
388                VertexDeclaration *pVertexDecl = pMesh->sharedVertexData->vertexDeclaration;
389
390                size_t offset = 0;
391
392                // position
393                pVertexDecl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
394                offset += VertexElement::getTypeSize(VET_FLOAT3);
395
396                // normals
397                if (mOgreMesh->drawNormals)
398                {
399                        pVertexDecl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
400                        offset += VertexElement::getTypeSize(VET_FLOAT3);
401                }
402
403                // colour (diffuse, specular)
404
405                // texture coordinates
406                if (mOgreMesh->drawTexCoords)
407                {
408                        pVertexDecl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
409                        offset += VertexElement::getTypeSize(VET_FLOAT2);
410                }
411
412                HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
413            offset, pMesh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
414
415                // set vertex buffer binding so buffer 0 is bound to our vertex buffer
416                VertexBufferBinding* bind = pMesh->sharedVertexData->vertexBufferBinding; 
417                bind->setBinding(0, vbuf);
418                // upload the vertex data to the card
419                vbuf->writeData(0, vbuf->getSizeInBytes(), mOgreMesh->vertices, true);
420
421                // for each polygon create a new submesh, for multimaterial e.g.
422                // submesh with index buffer
423                for (ColladaGeometryOgreMeshIndexData::iterator it = mOgreMesh->indices.begin(); it != mOgreMesh->indices.end(); ++it)
424                {
425                        SubMesh *pSubMesh = pMesh->createSubMesh();
426                        pSubMesh->indexData->indexCount = (*it)->count;
427                        pSubMesh->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
428                                HardwareIndexBuffer::IT_16BIT, pSubMesh->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
429                        HardwareIndexBufferSharedPtr ibuf = pSubMesh->indexData->indexBuffer;
430                        // upload the index data
431                        ibuf->writeData(0, ibuf->getSizeInBytes(), (*it)->indices, true);
432                       
433                        if (!(*it)->material.empty()) pSubMesh->setMaterialName((*it)->material);
434                        pSubMesh->useSharedVertices = true;
435                        pSubMesh->operationType = RenderOperation::OT_TRIANGLE_LIST;
436                }
437
438                // there should be an AABB in every case, maybe overwritten from the collada scene node import
439                // be careful by AABB if the object is duplicated and translated
440                pMesh->_setBounds(mBB->getAABB());
441                pMesh->_setBoundingSphereRadius(mBB->getRadius());
442
443                pMesh->load();
444        }
445
446        //-------------------------------------------------------------------------
447        bool ColladaGeometry::doImport(void)
448        {
449                if (mLoaded) return mStatus;
450                else mLoaded = true;
451
452                // get <mesh> node, must occur exactly one time [1,1]
453                xmlNode *mesh = ColladaUtils::getChildByTagName(mNode, CS_ELM_MESH);
454                if (mesh != NULL) mStatus = importMesh(mesh);
455
456                // get <extra> nodes, can occur [0,*]
457                // xmlNodePtrVector extras = ColladaUtils::getChildsByTagName(mNode, CS_ELM_EXTRA);
458                // for (xmlNodePtrVector::iterator i = extras.begin(); i != extras.end(); ++i) importExtra((*i));
459
460                if (mStatus) 
461                {
462                        calcBoundingBox();
463
464                        // create the vertices and indices by simple triangulation
465                        if (mType == POLYGONS || mType == TRIANGLES) createTriangleList();
466                }
467       
468                return mStatus;
469        }
470
471        //-------------------------------------------------------------------------
472        void ColladaGeometry::importExtra(xmlNode *extraNode)
473        {
474                // not yet implemented
475        }
476
477        //-------------------------------------------------------------------------
478        bool ColladaGeometry::importMesh(xmlNode *meshNode)
479        {
480                bool bPrimitives = false;
481
482                // vertices must occur exactly one time
483                if (!importVerticesNode(meshNode)) return false;
484
485                // look for polygon primitives
486                bPrimitives = importPolygonsNodes(meshNode, CS_ELM_POLYGONS);
487                if (bPrimitives)
488                {
489                        mType = POLYGONS;
490                        return true;
491                }
492
493        // triangles
494                bPrimitives = importPolygonsNodes(meshNode, CS_ELM_TRIANGLES);
495                if (bPrimitives)
496                {
497                        mType = TRIANGLES;
498                        return true;
499                }
500
501                return false;
502        }
503
504        //-------------------------------------------------------------------------
505        bool ColladaGeometry::importPolygonsNodes(xmlNode *meshNode, const String &primitive)
506        {
507                // there can be more than one <polygons> node, e.g. multi materials
508                xmlNodePtrVector polygonsNodes = ColladaUtils::getChildsByTagName(meshNode, primitive);
509                if (polygonsNodes.empty()) return false;
510
511                // walk through all <polygons>
512                for (xmlNodePtrVector::iterator it = polygonsNodes.begin(); it != polygonsNodes.end(); ++it)
513                {
514                        xmlNode *polygonsNode = *it;
515
516                        ColladaGeometryPolygon *polygon = new ColladaGeometryPolygon();
517
518                        // attribute material refers to a <material> node
519                        String material = ColladaUtils::getProperty(polygonsNode, CS_ATR_INPUT_MATERIAL);
520                        polygon->setMaterial = false;
521                        // search for material, get ptr
522                        if (!material.empty())
523                        {
524                                material.erase(0,1);    // remove the # sign
525                                polygon->material = mDoc->getLibrary()->getMaterial(material);
526                                if (polygon->material != NULL)
527                                {
528                                        // import material entity
529                                        if (!(polygon->setMaterial = polygon->material->doImport()))
530                                        {
531                                                LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - loading of assigned material " + material + " failed! " + mId);
532                                        }
533                                }
534                                else
535                                {
536                                        LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - can't find assigned material with id " + material + "! " + mId);
537                                }
538                        }
539
540                        // the number of polygon primitives
541                        String count = ColladaUtils::getProperty(polygonsNode, CS_ATR_COUNT);
542                        polygon->primitiveCount = (!count.empty()) ? static_cast<uint>(atoi(count.c_str())) : 0;
543
544                        // walk through <param>, <input>, <p> childs
545                        xmlNode *c = NULL;
546                        for (c = polygonsNode->children; c != NULL; c = c->next)
547                        {
548                                if (c->type != XML_ELEMENT_NODE) continue;
549                                String tagname = (const char *)c->name;
550
551                                // <param>, ignore it
552                                if (tagname == CS_ELM_PARAM) continue;
553                                // <input>
554                                else if (tagname == CS_ELM_INPUT)
555                                {
556                                        // get semantic attribute
557                                        String semantic = ColladaUtils::getProperty(c, CS_ATR_INPUT_SEMANTIC);                 
558                                        ColladaGeometrySpecific::Semantic tmpsemantic = ColladaGeometrySpecific::getSemantic(semantic);
559
560                                        if (tmpsemantic == ColladaGeometrySpecific::VERTEX ||
561                                                tmpsemantic == ColladaGeometrySpecific::NORMAL ||
562                                                tmpsemantic == ColladaGeometrySpecific::TEXCOORD)
563                                        {
564                                                // if (tmpsemantic == ColladaGeometryInput::NORMAL) mhasFaceNormals = true;
565                                                // if (tmpsemantic == ColladaGeometryInput::TEXCOORD) mhasFaceTexCoords = true;
566
567                                                String idx              = ColladaUtils::getProperty(c, CS_ATR_IDX);
568                                                String source   = ColladaUtils::getProperty(c, CS_ATR_INPUT_SOURCE);
569
570                                                ColladaGeometrySource *gsource = NULL;
571                                                // the source node points at <vertices>, already imported by importVerticesNode
572                                                if (tmpsemantic != ColladaGeometrySpecific::VERTEX)
573                                                {
574                                                        gsource = importSourceNode(ColladaUtils::getChildById(meshNode, source.c_str()));
575                                                        if (gsource == NULL)
576                                                        {
577                                                                LogManager::getSingleton().logMessage("ColladaGeometry::importVerticesNode - unable to find/import <source> with id " + source);
578                                                                continue;
579                                                        }
580                                                }
581
582                                                // make new inputdata and push it on the vector
583                                                ColladaGeometryInputData *input = new ColladaGeometryInputData();
584                                                input->idx = (!idx.empty()) ? static_cast<uint>(atoi(idx.c_str())) : polygon->inputs.size();
585                                                input->semantic = tmpsemantic;
586                                                input->source = gsource;
587
588                                                // check for duplicate <input>
589                                                bool idxrepeat = false;
590                                                for (ColladaGeometryInputDataPtrVector::iterator jt = polygon->inputs.begin(); jt != polygon->inputs.end() && !idxrepeat; ++jt)
591                                                {
592                                                        if ((*jt)->idx == input->idx) idxrepeat = true;
593                                                }
594                                                if (!idxrepeat) polygon->inputs.push_back(input);
595                                                else OGRE_DELETE(input);        // free unneeded geometry input data
596                                        }
597                                        // unknwon or unsupported
598                                        else
599                                        {
600                                                LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNode - unknown <semantic> " + semantic + " in <geometry> " + mId);
601                                                continue;                                       
602                                        }
603                                }
604                                // <p> first appearance, break, cause we will parse the primitves later
605                                else if (tagname == CS_ELM_P) break;
606                                // unknwon or unsupported
607                                else
608                                {
609                                        LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - unknown child: " + tagname);
610                                        continue;
611                                }
612                        }
613
614                        // there should be at least one <input> with semantic="VERTEX"
615                        if (polygon->inputs.at(0)->semantic != ColladaGeometrySpecific::VERTEX) continue;
616                        polygon->inputCount = static_cast<uint>(polygon->inputs.size()); 
617                       
618                        uint indexCount = 0;
619                        polygon->vertexCount = 0;
620                        uint tmppCount = 0;
621
622                        // parse primitives, <p> nodes, line by line
623                        for (; c != NULL; c = c->next)
624                        {
625                                if (c->type != XML_ELEMENT_NODE) continue;
626
627                                // get all indices (vertices, normals, texcoords)
628                                // ATTENTION: holes <h/> are currently not supported !!
629                                String primitive = ColladaUtils::getContentDirect(c);
630
631                                // split the primitive string
632                                StringVector sallindices = StringUtil::split(primitive," ");
633                                if (sallindices.empty()) continue;
634                               
635                                // get the amount of vertex indices of one polygon, quad patches are pleasant
636                                indexCount = static_cast<uint>(sallindices.size()) / polygon->inputCount;
637                                if (indexCount != polygon->vertexCount)
638                                {
639                                        // skip the false primitive line, but be aware of false geometries (e.g. holes)!
640                                        // perhaps it is better to stop reading immediately?
641                                        if (polygon->vertexCount > 0)
642                                        {
643                                                LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - different index count? " + mId);
644                                                LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - primitive: " + primitive);
645                                                continue;
646                                        }
647                                        polygon->vertexCount = indexCount;
648                                }
649
650                                // we can parse more than quad patches
651                                // but should we do this? currently there is only a simple algortihm which triangulate
652                                if (polygon->vertexCount > 4)
653                                {
654                                        LogManager::getSingleton().logMessage("ColladaGeometry::importPolygonsNodes - why are you not using quad patches?");                                   
655                                }
656
657                                intVector iallindices;
658                                iallindices.reserve(sallindices.size());
659
660                                // fill up a temp indices vector with conversions to int
661                                for (StringVector::iterator st = sallindices.begin(); st != sallindices.end(); ++st)
662                                {
663                                        iallindices.push_back(atoi((*st).c_str()));
664                                }
665
666                                // fill up the corresponding index vectors with indices
667                                for (uint offset = 0; offset < static_cast<uint>(iallindices.size()); offset += polygon->inputCount)
668                                {
669                                        // in order of inputs
670                                        for (ColladaGeometryInputDataPtrVector::iterator pt = polygon->inputs.begin(); pt != polygon->inputs.end(); ++pt)
671                                        {
672                                                (*pt)->indices.push_back(iallindices[offset + (*pt)->idx]);
673                                        }
674                                }
675
676                                tmppCount++;
677                        }
678
679                        // if there was a failure in parsing primitives, the amount is not still the same
680                        if (tmppCount < polygon->primitiveCount) polygon->primitiveCount = tmppCount;
681
682                        mPolygons.push_back(polygon);
683                }
684
685                return true;
686        }
687
688        //-------------------------------------------------------------------------
689        ColladaGeometrySource *ColladaGeometry::importSourceNode(xmlNode *sourceNode)
690        {
691                if (sourceNode == NULL) return NULL;
692
693                // get unique identifier
694                String id = ColladaUtils::getProperty(sourceNode, CS_ATR_ID);
695
696                // check if source is already loaded
697                for (ColladaGeometrySourcePtrVector::iterator itsource = mSources.begin(); itsource != mSources.end(); ++itsource)
698                {
699                        if ((*itsource)->id == id) return *itsource;
700                }
701
702                // get all <technique> child nodes
703                xmlNodePtrVector techniques = ColladaUtils::getChildsByTagName(sourceNode, CS_ELM_TECHNIQUE);
704               
705                // currently we are only interested in "COMMON" profile
706                xmlNode *technique = NULL;
707                for (xmlNodePtrVector::iterator it = techniques.begin(); it != techniques.end(); ++it)
708                {
709                        String profile = ColladaUtils::getProperty(*it, CS_ATR_PROFILE);
710                        if (profile == CS_VAL_TECHNIQUE_PROFILE_COMMON) 
711                        {
712                                technique = *it;
713                                break;
714                        }
715                }
716                if (technique == NULL) return NULL;
717
718                // currently ignore <asset>, <param>
719                // get <accessor> information
720                xmlNode *accessor = ColladaUtils::getChildByTagName(technique, CS_ELM_ACCESSOR);
721                if (accessor == NULL) return NULL;
722                // currently ignore <combiner>, <joints>, <program>
723
724                // get count and stride properties
725                String count = ColladaUtils::getProperty(accessor, CS_ATR_COUNT);
726                String stride = ColladaUtils::getProperty(accessor, CS_ATR_ACCESSOR_STRIDE);
727
728                // new source record
729                ColladaGeometrySource *source = new ColladaGeometrySource();
730                source->id = id;
731                source->count = (!count.empty()) ? static_cast<uint>(atoi(count.c_str())) : 0;
732                source->stride = (!stride.empty()) ? static_cast<uint>(atoi(stride.c_str())) : 0;
733
734                // get data from <float_array>
735                xmlNode *data = ColladaUtils::getChildByTagName(sourceNode, CS_ELM_FLOAT_ARRAY);
736                if (data == NULL) return NULL;
737
738                String content = ColladaUtils::getContentDirect(data);
739                if (content.empty()) return NULL;
740
741                // split string data by carriage return and line feed
742                StringVector lines = StringUtil::split(content,"\r\n");
743                if (lines.size() != source->count) source->count = static_cast<uint>(lines.size());
744                // reserve enough space
745                source->data.reserve(source->count * source->stride);
746                // walk through each data per line
747                for (StringVector::iterator jt = lines.begin(); jt != lines.end(); ++jt)
748                {       
749                        // split each line by a blank
750                        StringVector line = StringUtil::split(*jt," ");
751                        // for vertices (x, y, z), normals (x, y, z), texcoord (s, t), ...
752                        for (StringVector::iterator kt = line.begin(); kt != line.end(); ++kt)
753                        {
754                source->data.push_back( StringConverter::parseReal(*kt) );
755                        }
756                }
757
758                mSources.push_back(source);
759
760                return source;
761        }
762
763        //-------------------------------------------------------------------------
764        bool ColladaGeometry::importVerticesNode(xmlNode *meshNode)
765        {               
766                // get <vertices ...> node of mesh
767                xmlNode *vertices = ColladaUtils::getChildByTagName(meshNode, CS_ELM_VERTICES);
768                if (vertices == NULL)
769                {
770                        LogManager::getSingleton().logMessage("ColladaGeometry::importVerticesNode - no <vertices> node found in <geometry> " + mId);
771                        return false;
772                }
773
774                // walk through <input> childs
775                for (xmlNode *c = vertices->children; c != NULL; c = c->next)
776                {
777                        if (c->type != XML_ELEMENT_NODE) continue;
778
779                        String tagname = (const char *)c->name;
780                        // <input>
781                        if (tagname == CS_ELM_INPUT)
782                        {
783                                // get semantic attribute type
784                                String semantic = ColladaUtils::getProperty(c, CS_ATR_INPUT_SEMANTIC);
785                                ColladaGeometrySpecific::Semantic tmpsemantic = ColladaGeometrySpecific::getSemantic(semantic);
786                               
787                                if (tmpsemantic == ColladaGeometrySpecific::POSITION ||
788                    tmpsemantic == ColladaGeometrySpecific::NORMAL || 
789                                        tmpsemantic == ColladaGeometrySpecific::COLOR ||
790                                        tmpsemantic == ColladaGeometrySpecific::TEXCOORD) 
791                                {
792                                        // if (tmpsemantic == ColladaGeometryInput::NORMAL) mhasNormals = true;
793                                        // if (tmpsemantic == ColladaGeometryInput::TEXCOORD) mhasTexCoords = true;
794
795                                        // get source string
796                                        String source = ColladaUtils::getProperty(c, CS_ATR_INPUT_SOURCE);
797                                        if (source.empty()) continue;
798
799                                        // import source
800                                        ColladaGeometrySource *gsource = importSourceNode(ColladaUtils::getChildById(meshNode, source.c_str()));
801                                        if (gsource == NULL)
802                                        {
803                                                LogManager::getSingleton().logMessage("ColladaGeometry::importVerticesNode - unable to find/import <source> with id " + source);
804                                                continue;
805                                        }
806
807                                        // make new inputdata and push it on the vector
808                                        ColladaGeometryInputData *idata = new ColladaGeometryInputData();
809                                        idata->semantic = tmpsemantic;
810                                        idata->source = gsource;
811
812                                        mVertexInputs.push_back(idata);
813                                }
814                                // unknown or unsupported
815                                else
816                                {
817                                        LogManager::getSingleton().logMessage("ColladaGeometry::importVerticesNode - unknown <semantic> " + semantic + " in <geometry> " + mId);
818                                        continue;
819                                }
820                        }
821                        // unknown or unsupported
822                        else
823                        {
824                                LogManager::getSingleton().logMessage("ColladaGeometry::importVerticesNode - unknown child: " + tagname);
825                        }
826                }
827
828                // there must be at least one <input semantic="POSITION" ...>
829                return (mVertexInputs.at(0)->semantic == ColladaGeometrySpecific::POSITION);
830        }
831
832        //----------------------------------------------------------------------------
833        void ColladaGeometry::printIndices(void)
834        {
835                LogManager::getSingleton().logMessage(StringConverter::toString(mOgreMesh->indices.size()));
836                for (ColladaGeometryOgreMeshIndexData::iterator it = mOgreMesh->indices.begin(); it != mOgreMesh->indices.end(); ++it)
837                {
838                        String result = "";
839                        for (uint i = 0; i < (*it)->count; i++)
840                        {
841                                if (i % 3 == 0) result += "\n";
842                                result += " " + StringConverter::toString((*it)->indices[i]);
843                        }
844                        LogManager::getSingleton().logMessage(result + " " + StringConverter::toString((*it)->count) + " " + (*it)->material);
845                }
846        }
847
848        //----------------------------------------------------------------------------
849        void ColladaGeometry::printVertices(const unsigned short x)
850        {
851                String result = "";
852                LogManager::getSingleton().logMessage(StringConverter::toString(mOgreMesh->vertexCount));
853                for (uint i = 0; i < mOgreMesh->vertexCount * x; i++)
854                {
855                        if (i % x == 0) result += "\n";
856                        result += " " + StringConverter::toString(mOgreMesh->vertices[i]);
857                }
858                LogManager::getSingleton().logMessage(result);
859        }
860
861        //----------------------------------------------------------------------------
862        void ColladaGeometry::setBoundingBox(ColladaBoundingBox *b)
863        { 
864                if (mBB == NULL) return;
865
866                mBB = b;
867                mBBReset = true;
868        }
869
870        //----------------------------------------------------------------------------
871        namespace ColladaGeometrySpecific
872        {
873                Semantic getSemantic(const String &s)
874                {
875                        if (s == CS_VAL_INPUT_SEMANTIC_POSITION) return POSITION;
876                        else if (s == CS_VAL_INPUT_SEMANTIC_VERTEX) return VERTEX;
877                        else if (s == CS_VAL_INPUT_SEMANTIC_NORMAL) return NORMAL;
878                        else if (s == CS_VAL_INPUT_SEMANTIC_TEXCOORD) return TEXCOORD;
879                        else if (s == CS_VAL_INPUT_SEMANTIC_COLOR) return COLOR;
880                        else return UNKNOWN;
881                }
882        }
883}
Note: See TracBrowser for help on using the repository browser.