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 | |
---|
39 | namespace 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 | } |
---|