1 | #include "Exporter.h" |
---|
2 | #include <iostream> |
---|
3 | #include <string> |
---|
4 | #include "stdafx.h" |
---|
5 | #include "SemanticLayer.h" |
---|
6 | #include "OgreException.h" |
---|
7 | #include "OgreLogManager.h" |
---|
8 | #include "OgreMeshManager.h" |
---|
9 | #include "OgreSkeletonManager.h" |
---|
10 | #include "OgreAnimation.h" |
---|
11 | #include "OgreAnimationTrack.h" |
---|
12 | #include "OgreKeyFrame.h" |
---|
13 | #include "OgreMesh.h" |
---|
14 | #include "OgreSubMesh.h" |
---|
15 | #include "OgreSkeleton.h" |
---|
16 | #include "OgreBone.h" |
---|
17 | #include "OgreDefaultHardwareBufferManager.h" |
---|
18 | #include "OgreMeshSerializer.h" |
---|
19 | #include "OgreSkeletonSerializer.h" |
---|
20 | #include "OgrePrerequisites.h" |
---|
21 | #include "OgreVector2.h" |
---|
22 | #include "OgreVector3.h" |
---|
23 | #include "OgreVector3.h" |
---|
24 | #include "OgreColourValue.h" |
---|
25 | |
---|
26 | using namespace Ogre; |
---|
27 | |
---|
28 | //----------------------- GLOBALS FOR SINGLETONS ------------- |
---|
29 | LogManager* logMgr; |
---|
30 | ResourceGroupManager* rgm; |
---|
31 | MeshManager* meshMgr; |
---|
32 | DefaultHardwareBufferManager* hardwareBufMgr; |
---|
33 | SkeletonManager* skelMgr; |
---|
34 | |
---|
35 | //------------------------------------------------------------ |
---|
36 | Exporter::UniqueVertex::UniqueVertex() |
---|
37 | : initialized(false), position(Ogre::Vector3::ZERO), normal(Ogre::Vector3::ZERO), color(0), |
---|
38 | nextIndex(0) |
---|
39 | { |
---|
40 | for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i) |
---|
41 | uv[i] = Ogre::Vector2::ZERO; |
---|
42 | } |
---|
43 | |
---|
44 | //------------------------------------------------------------ |
---|
45 | bool Exporter::UniqueVertex::operator ==(const UniqueVertex& rhs) const |
---|
46 | { |
---|
47 | bool ret = position == rhs.position && |
---|
48 | normal == rhs.normal && |
---|
49 | color == rhs.color; |
---|
50 | if (!ret) return ret; |
---|
51 | for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS && ret; ++i) |
---|
52 | { |
---|
53 | ret = ret && (uv[i] == rhs.uv[i]); |
---|
54 | } |
---|
55 | return ret; |
---|
56 | } |
---|
57 | |
---|
58 | //------------------------------------------------------------ |
---|
59 | Exporter::Exporter(CSLModel * Root) |
---|
60 | { |
---|
61 | // Initialize Exporter object instance variables |
---|
62 | this->SceneRoot = Root; |
---|
63 | boneCount = 0; |
---|
64 | } |
---|
65 | |
---|
66 | //------------------------------------------------------------ |
---|
67 | Exporter::~Exporter() |
---|
68 | { |
---|
69 | } |
---|
70 | |
---|
71 | //------------------------------------------------------------ |
---|
72 | void Exporter::exportMesh(std::string fileName, std::string skelName) |
---|
73 | { |
---|
74 | // Construct mesh |
---|
75 | MeshPtr pMesh = MeshManager::getSingleton().createManual(fileName, ResourceGroupManager:: |
---|
76 | DEFAULT_RESOURCE_GROUP_NAME); |
---|
77 | pMesh->setSkeletonName(skelName); |
---|
78 | |
---|
79 | // We'll assume we want to export the entire scene |
---|
80 | exportCSLModel(pMesh.getPointer(), SceneRoot); |
---|
81 | MeshSerializer serializer; |
---|
82 | serializer.exportMesh(pMesh.getPointer(), fileName); |
---|
83 | } |
---|
84 | |
---|
85 | //-------------------------------------------------------------------------- |
---|
86 | void Exporter::exportCSLModel(Mesh* pMesh, CSLModel* XSIModel) |
---|
87 | { |
---|
88 | if (XSIModel->GetPrimitiveType() == CSLTemplate::SI_MESH) |
---|
89 | exportSubMesh(pMesh, (CSLMesh *) XSIModel->Primitive()); |
---|
90 | |
---|
91 | CSLModel* *l_childrenList = XSIModel->GetChildrenList(); |
---|
92 | |
---|
93 | // Loop through all children |
---|
94 | for (int i = 0; i < XSIModel->GetChildrenCount(); i++ ) |
---|
95 | { |
---|
96 | exportCSLModel (pMesh, l_childrenList[i]); |
---|
97 | } |
---|
98 | } |
---|
99 | |
---|
100 | //------------------------------------------------------------------------- |
---|
101 | void Exporter::exportSubMesh(Mesh *pMesh, CSLMesh* XSIMesh) |
---|
102 | { |
---|
103 | SubMesh* sm = 0; |
---|
104 | sm = pMesh->createSubMesh(XSIMesh->GetName()); |
---|
105 | |
---|
106 | // HACK: No materials exporter yet, I hard coded this, wrong as hell, but did it anyway |
---|
107 | // For now, I'm just creating the materials file manually. |
---|
108 | sm->setMaterialName("Examples/Woman"); |
---|
109 | CSLTriangleList** triangles = XSIMesh->TriangleLists(); |
---|
110 | |
---|
111 | // Assume only one triangle list for now |
---|
112 | CSLTriangleList* triArray = triangles[0]; |
---|
113 | std::cout << "Number of triangles: " << triArray->GetTriangleCount() << "\n"; |
---|
114 | CSIBCVector3D* srcPosArray = XSIMesh->Shape()->GetVertexListPtr(); |
---|
115 | std::cout << "Number of vertices: " << XSIMesh->Shape()->GetVertexCount() << "\n"; |
---|
116 | CSIBCVector3D* srcNormArray = XSIMesh->Shape()->GetNormalListPtr(); |
---|
117 | std::cout << "Number of normals: " << XSIMesh->Shape()->GetNormalCount() << "\n"; |
---|
118 | CSLShape_35 * uv = ((CSLShape_35 *) XSIMesh->Shape()); |
---|
119 | size_t numUVs = uv->UVCoordArrays()[0]->GetUVCoordCount(); |
---|
120 | std::cout << "Number of UVs: " << numUVs << "\n"; |
---|
121 | |
---|
122 | // For now, assume only one set of UV's |
---|
123 | CSIBCVector2D* uvValueArray = ((CSLShape_35 *) XSIMesh->Shape())->UVCoordArrays()[0]->GetUVCoordListPtr(); |
---|
124 | |
---|
125 | // Check for colors |
---|
126 | bool hasVertexColors = false; |
---|
127 | if (XSIMesh->Shape()->GetColorCount() > 0) |
---|
128 | hasVertexColors = true; |
---|
129 | |
---|
130 | // Never use shared geometry |
---|
131 | sm->useSharedVertices = false; |
---|
132 | sm->vertexData = new VertexData(); |
---|
133 | |
---|
134 | // Always do triangle list |
---|
135 | sm->indexData->indexCount = static_cast<size_t>(triArray->GetTriangleCount() * 3); |
---|
136 | |
---|
137 | // Identify the unique vertices, write to a temp index buffer |
---|
138 | startPolygonMesh(XSIMesh->Shape()->GetVertexCount(), triArray->GetTriangleCount() * 3); |
---|
139 | |
---|
140 | // Iterate through all the triangles |
---|
141 | // There will often be less positions than normals and UV's |
---|
142 | for (long t = 0; t < triArray->GetTriangleCount(); ++t) |
---|
143 | { |
---|
144 | for (int p = 0; p < 3; ++p) |
---|
145 | { |
---|
146 | UniqueVertex vertex; |
---|
147 | CSIBCVector3D pos = srcPosArray[triArray->GetVertexIndicesPtr()[t*3+p]]; |
---|
148 | CSIBCVector3D norm = srcNormArray[triArray->GetNormalIndicesPtr()[t*3+p]]; |
---|
149 | CSIBCVector2D uv = uvValueArray[triArray->GetUVIndicesPtr(0)[t*3+p]]; |
---|
150 | vertex.position = Vector3(pos.GetX(), pos.GetY(), pos.GetZ()); |
---|
151 | vertex.normal = Vector3(norm.GetX(), norm.GetY(), norm.GetZ()); |
---|
152 | |
---|
153 | // We are assuming 1 UV -- in our files, number of UV's = number of Normals |
---|
154 | vertex.uv[0] = Vector2(uv.GetX(), (1 - uv.GetY())); |
---|
155 | |
---|
156 | if (hasVertexColors) |
---|
157 | vertex.color = triArray->GetColorIndicesPtr()[t*3+p]; |
---|
158 | size_t index = createOrRetrieveUniqueVertex(triArray->GetVertexIndicesPtr()[t*3+p], vertex); |
---|
159 | mIndices.push_back(index); |
---|
160 | } |
---|
161 | } |
---|
162 | delete [] uvValueArray; |
---|
163 | |
---|
164 | // Now bake final geometry |
---|
165 | sm->vertexData->vertexCount = mUniqueVertices.size(); |
---|
166 | |
---|
167 | // Determine index size |
---|
168 | bool use32BitIndexes = false; |
---|
169 | if (mUniqueVertices.size() > 65536) |
---|
170 | use32BitIndexes = true; |
---|
171 | sm->indexData->indexBuffer = |
---|
172 | HardwareBufferManager::getSingleton().createIndexBuffer( |
---|
173 | use32BitIndexes ? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT, |
---|
174 | triArray->GetTriangleCount() * 3, HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
175 | if (use32BitIndexes) |
---|
176 | { |
---|
177 | uint32* pIdx = static_cast<uint32*>( |
---|
178 | sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); |
---|
179 | writeIndexes(pIdx); |
---|
180 | sm->indexData->indexBuffer->unlock(); |
---|
181 | } |
---|
182 | else |
---|
183 | { |
---|
184 | uint16* pIdx = static_cast<uint16*>( |
---|
185 | sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); |
---|
186 | writeIndexes(pIdx); |
---|
187 | sm->indexData->indexBuffer->unlock(); |
---|
188 | } |
---|
189 | |
---|
190 | // Define vertex declaration |
---|
191 | unsigned buf = 0; |
---|
192 | size_t offset = 0; |
---|
193 | sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_POSITION); |
---|
194 | offset += VertexElement::getTypeSize(VET_FLOAT3); |
---|
195 | sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_NORMAL); |
---|
196 | offset += VertexElement::getTypeSize(VET_FLOAT3); |
---|
197 | // TODO: Split Vertex Data if animated |
---|
198 | |
---|
199 | if (hasVertexColors) |
---|
200 | { |
---|
201 | sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_COLOUR, VES_DIFFUSE); |
---|
202 | offset += VertexElement::getTypeSize(VET_COLOUR); |
---|
203 | } |
---|
204 | |
---|
205 | // Again, assume only 1 uv |
---|
206 | sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); |
---|
207 | offset += VertexElement::getTypeSize(VET_FLOAT2); |
---|
208 | |
---|
209 | // Create and fill buffer(s) |
---|
210 | for (unsigned short b = 0; b <= sm->vertexData->vertexDeclaration->getMaxSource(); ++b) |
---|
211 | { |
---|
212 | createVertexBuffer(sm->vertexData, b); |
---|
213 | } |
---|
214 | |
---|
215 | // Bounds definitions |
---|
216 | Real squaredRadius = 0.0f; |
---|
217 | Vector3 min, max; |
---|
218 | bool first = true; |
---|
219 | for (long i = 0; i < XSIMesh->Shape()->GetVertexCount(); ++i) |
---|
220 | { |
---|
221 | Vector3 position = Vector3(srcPosArray[i].GetX(), srcPosArray[i].GetY(), srcPosArray[i].GetZ()); |
---|
222 | if (first) |
---|
223 | { |
---|
224 | squaredRadius = position.squaredLength(); |
---|
225 | min = max = position; |
---|
226 | first = false; |
---|
227 | } |
---|
228 | else |
---|
229 | { |
---|
230 | squaredRadius = std::max(squaredRadius, position.squaredLength()); |
---|
231 | min.makeFloor(position); |
---|
232 | max.makeCeil(position); |
---|
233 | } |
---|
234 | } |
---|
235 | AxisAlignedBox box; |
---|
236 | box.setExtents(min, max); |
---|
237 | box.merge(pMesh->getBounds()); |
---|
238 | pMesh->_setBounds(box); |
---|
239 | pMesh->_setBoundingSphereRadius(std::max(pMesh->getBoundingSphereRadius(), |
---|
240 | Math::Sqrt(squaredRadius))); |
---|
241 | |
---|
242 | // Get Envelope list for this submesh |
---|
243 | CSLEnvelope** envelopes = XSIMesh->ParentModel()->GetEnvelopeList(); |
---|
244 | CSLEnvelope* env = 0; |
---|
245 | int boneIdx; |
---|
246 | bool done; |
---|
247 | int index; |
---|
248 | VertexBoneAssignment vertAssign; |
---|
249 | for (int e = 0; e < XSIMesh->ParentModel()->GetEnvelopeCount(); ++e) |
---|
250 | { |
---|
251 | env = envelopes[e]; |
---|
252 | for (int g = 0; g < boneCount; ++g) |
---|
253 | { |
---|
254 | if (boneArray[g] == env->GetDeformer()->GetName()) |
---|
255 | boneIdx = g; |
---|
256 | else |
---|
257 | continue; |
---|
258 | break; |
---|
259 | } |
---|
260 | |
---|
261 | SLVertexWeight* wtList = env->GetVertexWeightListPtr(); |
---|
262 | |
---|
263 | // Go through all collocated vertices, assigning the same weights to each. |
---|
264 | // All the dotXSI files I've seen normalize the weights to 100, so for now |
---|
265 | // I'm just dividing by 100. TODO: Insert code to handle normalization |
---|
266 | // just in case. |
---|
267 | for (int h = 0; h < env->GetVertexWeightCount(); ++h) |
---|
268 | { |
---|
269 | vertAssign.boneIndex = boneIdx; |
---|
270 | vertAssign.vertexIndex = index = (int) wtList[h].m_fVertexIndex; |
---|
271 | vertAssign.weight = (Real) (wtList[h].m_fWeight / 100); |
---|
272 | done = false; |
---|
273 | while (!done) |
---|
274 | { |
---|
275 | sm->addBoneAssignment(vertAssign); |
---|
276 | if (mUniqueVertices[index].nextIndex) |
---|
277 | vertAssign.vertexIndex = index = mUniqueVertices[index].nextIndex; |
---|
278 | else |
---|
279 | done = true; |
---|
280 | } |
---|
281 | } |
---|
282 | } |
---|
283 | |
---|
284 | // Last step here is to reorganise the vertex buffers |
---|
285 | VertexDeclaration* newDecl = |
---|
286 | sm->vertexData->vertexDeclaration->getAutoOrganisedDeclaration(true); |
---|
287 | BufferUsageList bufferUsages; |
---|
288 | for (size_t u = 0; u <= newDecl->getMaxSource(); ++u) |
---|
289 | bufferUsages.push_back(HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
290 | sm->vertexData->reorganiseBuffers(newDecl, bufferUsages); |
---|
291 | } |
---|
292 | |
---|
293 | //----------------------------------------------------------------------------- |
---|
294 | template <typename T> |
---|
295 | void Exporter::writeIndexes(T* buf) |
---|
296 | { |
---|
297 | IndexList::const_iterator i, iend; |
---|
298 | iend = mIndices.end(); |
---|
299 | for (i = mIndices.begin(); i != iend; ++i) |
---|
300 | { |
---|
301 | *buf++ = static_cast<T>(*i); |
---|
302 | } |
---|
303 | } |
---|
304 | |
---|
305 | //----------------------------------------------------------------------------- |
---|
306 | void Exporter::createVertexBuffer(VertexData* vd, unsigned short bufIdx) |
---|
307 | { |
---|
308 | HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( |
---|
309 | vd->vertexDeclaration->getVertexSize(bufIdx), |
---|
310 | vd->vertexCount, |
---|
311 | HardwareBuffer::HBU_STATIC_WRITE_ONLY); |
---|
312 | vd->vertexBufferBinding->setBinding(bufIdx, vbuf); |
---|
313 | size_t vertexSize = vd->vertexDeclaration->getVertexSize(bufIdx); |
---|
314 | |
---|
315 | char* pBase = static_cast<char*>(vbuf->lock(HardwareBuffer::HBL_DISCARD)); |
---|
316 | |
---|
317 | VertexDeclaration::VertexElementList elems = vd->vertexDeclaration->findElementsBySource(bufIdx); |
---|
318 | VertexDeclaration::VertexElementList::iterator ei, eiend; |
---|
319 | eiend = elems.end(); |
---|
320 | float* pFloat; |
---|
321 | RGBA* pRGBA; |
---|
322 | |
---|
323 | Exporter::UniqueVertexList::iterator srci = mUniqueVertices.begin(); |
---|
324 | |
---|
325 | for (size_t v = 0; v < vd->vertexCount; ++v, ++srci) |
---|
326 | { |
---|
327 | for (ei = elems.begin(); ei != eiend; ++ei) |
---|
328 | { |
---|
329 | VertexElement& elem = *ei; |
---|
330 | switch(elem.getSemantic()) |
---|
331 | { |
---|
332 | case VES_POSITION: |
---|
333 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
334 | *pFloat++ = srci->position.x; |
---|
335 | *pFloat++ = srci->position.y; |
---|
336 | *pFloat++ = srci->position.z; |
---|
337 | break; |
---|
338 | case VES_NORMAL: |
---|
339 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
340 | *pFloat++ = srci->normal.x; |
---|
341 | *pFloat++ = srci->normal.y; |
---|
342 | *pFloat++ = srci->normal.z; |
---|
343 | break; |
---|
344 | case VES_DIFFUSE: |
---|
345 | elem.baseVertexPointerToElement(pBase, &pRGBA); |
---|
346 | *pRGBA = srci->color; |
---|
347 | break; |
---|
348 | case VES_TEXTURE_COORDINATES: |
---|
349 | elem.baseVertexPointerToElement(pBase, &pFloat); |
---|
350 | *pFloat++ = srci->uv[elem.getIndex()].x; |
---|
351 | *pFloat++ = srci->uv[elem.getIndex()].y; |
---|
352 | break; |
---|
353 | } |
---|
354 | } |
---|
355 | pBase += vertexSize; |
---|
356 | } |
---|
357 | vbuf->unlock(); |
---|
358 | } |
---|
359 | |
---|
360 | //---------------------------------------------------------------------- |
---|
361 | void Exporter::startPolygonMesh(size_t count, size_t indexCount) |
---|
362 | { |
---|
363 | mUniqueVertices.clear(); |
---|
364 | mUniqueVertices.resize(count); |
---|
365 | mIndices.clear(); |
---|
366 | mIndices.reserve(indexCount); // intentionally reserved, not resized |
---|
367 | } |
---|
368 | |
---|
369 | //---------------------------------------------------------------------- |
---|
370 | size_t Exporter::createOrRetrieveUniqueVertex(size_t originalPositionIndex, const UniqueVertex& vertex) |
---|
371 | { |
---|
372 | UniqueVertex& orig = mUniqueVertices[originalPositionIndex]; |
---|
373 | |
---|
374 | if (!orig.initialized) |
---|
375 | { |
---|
376 | orig = vertex; |
---|
377 | orig.initialized = true; |
---|
378 | return originalPositionIndex; |
---|
379 | } |
---|
380 | else if (orig == vertex) |
---|
381 | { |
---|
382 | return originalPositionIndex; |
---|
383 | } |
---|
384 | else |
---|
385 | { |
---|
386 | // no match, go to next or create new |
---|
387 | if (orig.nextIndex) |
---|
388 | { |
---|
389 | // cascade |
---|
390 | return createOrRetrieveUniqueVertex(orig.nextIndex, vertex); |
---|
391 | } |
---|
392 | else |
---|
393 | { |
---|
394 | // get new index |
---|
395 | size_t newindex = mUniqueVertices.size(); |
---|
396 | orig.nextIndex = newindex; |
---|
397 | // create new (NB invalidates 'orig' reference) |
---|
398 | mUniqueVertices.push_back(vertex); |
---|
399 | // set initialised |
---|
400 | mUniqueVertices[newindex].initialized = true; |
---|
401 | |
---|
402 | return newindex; |
---|
403 | } |
---|
404 | } |
---|
405 | } |
---|
406 | |
---|
407 | //------------------------------------------------------------------------------ |
---|
408 | void Exporter::exportBones(std::string fileName) |
---|
409 | { |
---|
410 | // Construct skeleton |
---|
411 | SkeletonPtr pSkel = SkeletonManager::getSingleton().create( fileName, ResourceGroupManager:: |
---|
412 | DEFAULT_RESOURCE_GROUP_NAME, true); |
---|
413 | |
---|
414 | // Recursively traverse the bone tree |
---|
415 | root = false; |
---|
416 | recurseBones(pSkel.getPointer(), SceneRoot); |
---|
417 | |
---|
418 | // Export animations |
---|
419 | exportAnim(pSkel.getPointer(), SceneRoot); |
---|
420 | |
---|
421 | // Call serializer to write .skeleton file |
---|
422 | SkeletonSerializer serializer; |
---|
423 | serializer.exportSkeleton(pSkel.getPointer(), fileName); |
---|
424 | } |
---|
425 | |
---|
426 | //----------------------------------------------------------------- |
---|
427 | void Exporter::recurseBones(Skeleton* pSkel, CSLModel* XSIModel) |
---|
428 | { |
---|
429 | CSIBCVector3D vec3d; |
---|
430 | |
---|
431 | // A plethora of logical expressions to ensure that the root null and |
---|
432 | // its children are the only ones that will enter this if block. Eliminates |
---|
433 | // any extraneous nulls not related to the skeleton. |
---|
434 | |
---|
435 | if ((XSIModel->GetPrimitiveType() == CSLTemplate::SI_NULL_OBJECT) && |
---|
436 | ((XSIModel->ParentModel()->GetPrimitiveType() == CSLTemplate::SI_NULL_OBJECT) || (!root))) |
---|
437 | { |
---|
438 | boneArray[boneCount] = XSIModel->GetName(); |
---|
439 | Bone* ogreBone = pSkel->createBone(XSIModel->GetName(), boneCount); |
---|
440 | root = true; |
---|
441 | vec3d = XSIModel->Transform()->GetScale(); |
---|
442 | ogreBone->setScale(vec3d.GetX(), vec3d.GetY(), vec3d.GetZ()); |
---|
443 | vec3d = XSIModel->Transform()->GetTranslation(); |
---|
444 | Vector3 bonePos(vec3d.GetX(), vec3d.GetY(), vec3d.GetZ()); |
---|
445 | ogreBone->setPosition(bonePos); |
---|
446 | |
---|
447 | // Yes, we are converting Euler angles to quaternions, at risk of gimbal lock. |
---|
448 | // This is because XSI doesn't export quaternions, except through the animation |
---|
449 | // mixer and action FCurves. It's possible to get a 3x3 Rotation matrix, which |
---|
450 | // might be a better choice for conversion to quaternion. |
---|
451 | vec3d = XSIModel->Transform()->GetEulerRotation(); |
---|
452 | Ogre::Quaternion qx, qy, qz, qfinal; |
---|
453 | qx.FromAngleAxis(Ogre::Degree(vec3d.GetX()), Ogre::Vector3::UNIT_X); |
---|
454 | qy.FromAngleAxis(Ogre::Degree(vec3d.GetY()), Ogre::Vector3::UNIT_Y); |
---|
455 | qz.FromAngleAxis(Ogre::Degree(vec3d.GetZ()), Ogre::Vector3::UNIT_Z); |
---|
456 | |
---|
457 | // Assume rotate by x then y then z |
---|
458 | qfinal = qz * qy * qx; |
---|
459 | ogreBone->setOrientation(qfinal); |
---|
460 | ++boneCount; |
---|
461 | |
---|
462 | if ((boneCount > 1) && (XSIModel->ParentModel()->GetPrimitiveType() == CSLTemplate::SI_NULL_OBJECT)) |
---|
463 | { |
---|
464 | pSkel->getBone(XSIModel->ParentModel()->GetName())->addChild(ogreBone); |
---|
465 | } |
---|
466 | } |
---|
467 | |
---|
468 | CSLModel* *l_childrenList = XSIModel->GetChildrenList(); |
---|
469 | |
---|
470 | // Loop through all children |
---|
471 | for (int i = 0; i < XSIModel->GetChildrenCount(); i++ ) |
---|
472 | { |
---|
473 | recurseBones (pSkel, l_childrenList[i]); |
---|
474 | } |
---|
475 | } |
---|
476 | |
---|
477 | //------------------------------------------------------------------------------ |
---|
478 | |
---|
479 | void Exporter::exportAnim(Skeleton* pSkel, CSLModel* XSIModel) |
---|
480 | { |
---|
481 | CSLTransform* initial; |
---|
482 | CSLTransform* keyfr = 0; |
---|
483 | CSIBCMatrix4x4 initmat, invinitmat, keyfmat, newmat; |
---|
484 | |
---|
485 | // Timing conversions from XSI frames to OGRE time in seconds |
---|
486 | float frameRate = XSIModel->Scene()->SceneInfo()->GetFrameRate(); |
---|
487 | float lengthInFrames = XSIModel->Scene()->SceneInfo()->GetEnd() - |
---|
488 | XSIModel->Scene()->SceneInfo()->GetStart(); |
---|
489 | float realTime = lengthInFrames / frameRate; |
---|
490 | |
---|
491 | // HACK: You'd want to assign the correct name to your particular animation. |
---|
492 | Animation *ogreanim = |
---|
493 | pSkel->createAnimation("Jump", realTime ); |
---|
494 | int i, numKeys; |
---|
495 | |
---|
496 | // Go to each bone and create the animation tracks |
---|
497 | for (i = 0; i < boneCount; ++i) |
---|
498 | { |
---|
499 | Bone* ogrebone = pSkel->getBone(boneArray[i]); |
---|
500 | CSLModel* XSIbone = XSIModel->Scene()->FindModelRecursively((char *) boneArray[i].c_str(), XSIModel); |
---|
501 | if ((i == 0) || (XSIbone->ParentModel()->GetPrimitiveType() == CSLTemplate::SI_NULL_OBJECT)) |
---|
502 | { |
---|
503 | // Create animation tracks for a bone |
---|
504 | AnimationTrack *ogretrack = ogreanim->createTrack(i, ogrebone); |
---|
505 | numKeys = XSIbone->Transform()->FCurves()[0]->GetKeyCount(); |
---|
506 | CSLLinearKey* scalx = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_SCALING_X)->GetLinearKeyListPtr(); |
---|
507 | CSLLinearKey* scaly = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_SCALING_Y)->GetLinearKeyListPtr(); |
---|
508 | CSLLinearKey* scalz = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_SCALING_Z)->GetLinearKeyListPtr(); |
---|
509 | CSLLinearKey* rotx = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_ROTATION_X)->GetLinearKeyListPtr(); |
---|
510 | CSLLinearKey* roty = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_ROTATION_Y)->GetLinearKeyListPtr(); |
---|
511 | CSLLinearKey* rotz = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_ROTATION_Z)->GetLinearKeyListPtr(); |
---|
512 | CSLLinearKey* tranx = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_TRANSLATION_X)->GetLinearKeyListPtr(); |
---|
513 | CSLLinearKey* trany = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_TRANSLATION_Y)->GetLinearKeyListPtr(); |
---|
514 | CSLLinearKey* tranz = XSIbone->Transform()->GetSpecificFCurve(CSLTemplate::SI_TRANSLATION_Z)->GetLinearKeyListPtr(); |
---|
515 | |
---|
516 | // Set up the bind pose matrix and take inverse |
---|
517 | initial = XSIbone->Transform(); |
---|
518 | initial->ComputeLocalMatrix(); |
---|
519 | initmat = initial->GetMatrix(); |
---|
520 | initmat.GetInverse(invinitmat); |
---|
521 | |
---|
522 | for (int currKeyIdx = 0; currKeyIdx < numKeys; ++currKeyIdx) |
---|
523 | { |
---|
524 | // Create keyframe |
---|
525 | // Adjust for start time, and for the fact that frames are numbered from 1 |
---|
526 | float frameTime = scalx[currKeyIdx].m_fTime - XSIModel->Scene()->SceneInfo()->GetStart(); |
---|
527 | realTime = frameTime / frameRate; |
---|
528 | KeyFrame *ogrekey = ogretrack->createKeyFrame(realTime); |
---|
529 | keyfr = XSIbone->Transform(); |
---|
530 | keyfr->SetScale(CSIBCVector3D(scalx[currKeyIdx].m_fValue, scaly[currKeyIdx].m_fValue, scalz[currKeyIdx].m_fValue)); |
---|
531 | keyfr->SetEulerRotation(CSIBCVector3D(rotx[currKeyIdx].m_fValue, roty[currKeyIdx].m_fValue, rotz[currKeyIdx].m_fValue)); |
---|
532 | keyfr->SetTranslation(CSIBCVector3D(tranx[currKeyIdx].m_fValue, trany[currKeyIdx].m_fValue, tranz[currKeyIdx].m_fValue)); |
---|
533 | keyfr->ComputeLocalMatrix(); |
---|
534 | keyfmat = keyfr->GetMatrix(); |
---|
535 | |
---|
536 | // Inverse bind pose matrix * keyframe transformation matrix |
---|
537 | invinitmat.Multiply(keyfmat, newmat); |
---|
538 | CSIBCVector3D kfSca, kfRot, kfPos; |
---|
539 | newmat.GetTransforms(kfSca, kfRot, kfPos); |
---|
540 | Vector3 kSca(kfSca.GetX(), kfSca.GetY(), kfSca.GetZ()); |
---|
541 | Vector3 kPos(kfPos.GetX(), kfPos.GetY(), kfPos.GetZ()); |
---|
542 | Quaternion qx, qy, qz, kfQ; |
---|
543 | ogrekey->setScale(kSca); |
---|
544 | ogrekey->setTranslate(kPos); |
---|
545 | qx.FromAngleAxis(Ogre::Radian(kfRot.GetX()), Vector3::UNIT_X); |
---|
546 | qy.FromAngleAxis(Ogre::Radian(kfRot.GetY()), Vector3::UNIT_Y); |
---|
547 | qz.FromAngleAxis(Ogre::Radian(kfRot.GetZ()), Vector3::UNIT_Z); |
---|
548 | kfQ = qz * qy * qx; |
---|
549 | ogrekey->setRotation(kfQ); |
---|
550 | } |
---|
551 | } |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | //------------------------------------------------------------------------------ |
---|
556 | int main(int argc, char *argv[]) |
---|
557 | { |
---|
558 | // Validate command line arguments |
---|
559 | if (argc != 3) { |
---|
560 | std::cout << "XSI Ogre Exporter should be invoked in the format: \n"; |
---|
561 | std::cout << "exporter <XSI File> <OGRE Mesh/Skeleton File>\n"; |
---|
562 | std::cout << "Ex: exporter example.xsi example\n"; |
---|
563 | return (0); |
---|
564 | } |
---|
565 | |
---|
566 | // Ogre Singletons |
---|
567 | logMgr = new LogManager(); |
---|
568 | logMgr->createLog("XSIOgreExport"); |
---|
569 | rgm = new ResourceGroupManager(); |
---|
570 | meshMgr = new MeshManager(); |
---|
571 | hardwareBufMgr = new DefaultHardwareBufferManager(); |
---|
572 | skelMgr = new SkeletonManager(); |
---|
573 | |
---|
574 | // Initialize dotXSI Scene |
---|
575 | CSLScene Scene; |
---|
576 | std::string fn(argv[2]); |
---|
577 | std::string meshFileName = fn + ".mesh"; |
---|
578 | std::string skelFileName = fn + ".skeleton"; |
---|
579 | |
---|
580 | // Continue if valid dotXSI file, end gracefully if not |
---|
581 | if (Scene.Open(argv[1]) == SI_SUCCESS) |
---|
582 | { |
---|
583 | Scene.Read(); |
---|
584 | Exporter * e = new Exporter(Scene.Root()); |
---|
585 | e->exportBones(skelFileName); |
---|
586 | e->exportMesh(meshFileName, skelFileName); |
---|
587 | delete e; |
---|
588 | Scene.Close(); |
---|
589 | } |
---|
590 | else |
---|
591 | std::cout << "Error opening file " << argv[1] << ". Please check for validity.\n"; |
---|
592 | |
---|
593 | // Get rid of Ogre Singletons |
---|
594 | delete skelMgr; |
---|
595 | delete meshMgr; |
---|
596 | delete hardwareBufMgr; |
---|
597 | delete rgm; |
---|
598 | delete logMgr; |
---|
599 | return (0); |
---|
600 | } |
---|