diff options
author | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
commit | 393b5cd1dc438872af89d334ef6e5fcc59f27d47 (patch) | |
tree | 6a14521219942a08a1b95cb2f5a923a9edd60f63 /libraries/irrlicht-1.8/source/Irrlicht/CSkinnedMesh.cpp | |
parent | Add a note about rasters suggested start up code. (diff) | |
download | SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.zip SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.gz SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.bz2 SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.xz |
Added Irrlicht 1.8, but without all the Windows binaries.
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CSkinnedMesh.cpp | 1471 |
1 files changed, 1471 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CSkinnedMesh.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CSkinnedMesh.cpp new file mode 100644 index 0000000..e1ab5a5 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CSkinnedMesh.cpp | |||
@@ -0,0 +1,1471 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ | ||
7 | |||
8 | #include "CSkinnedMesh.h" | ||
9 | #include "CBoneSceneNode.h" | ||
10 | #include "IAnimatedMeshSceneNode.h" | ||
11 | #include "os.h" | ||
12 | |||
13 | namespace irr | ||
14 | { | ||
15 | namespace scene | ||
16 | { | ||
17 | |||
18 | |||
19 | //! constructor | ||
20 | CSkinnedMesh::CSkinnedMesh() | ||
21 | : SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f), | ||
22 | LastAnimatedFrame(-1), SkinnedLastFrame(false), | ||
23 | InterpolationMode(EIM_LINEAR), | ||
24 | HasAnimation(false), PreparedForSkinning(false), | ||
25 | AnimateNormals(true), HardwareSkinning(false) | ||
26 | { | ||
27 | #ifdef _DEBUG | ||
28 | setDebugName("CSkinnedMesh"); | ||
29 | #endif | ||
30 | |||
31 | SkinningBuffers=&LocalBuffers; | ||
32 | } | ||
33 | |||
34 | |||
35 | //! destructor | ||
36 | CSkinnedMesh::~CSkinnedMesh() | ||
37 | { | ||
38 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
39 | delete AllJoints[i]; | ||
40 | |||
41 | for (u32 j=0; j<LocalBuffers.size(); ++j) | ||
42 | { | ||
43 | if (LocalBuffers[j]) | ||
44 | LocalBuffers[j]->drop(); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | |||
49 | //! returns the amount of frames in milliseconds. | ||
50 | //! If the amount is 1, it is a static (=non animated) mesh. | ||
51 | u32 CSkinnedMesh::getFrameCount() const | ||
52 | { | ||
53 | return core::floor32(AnimationFrames); | ||
54 | } | ||
55 | |||
56 | |||
57 | //! Gets the default animation speed of the animated mesh. | ||
58 | /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ | ||
59 | f32 CSkinnedMesh::getAnimationSpeed() const | ||
60 | { | ||
61 | return FramesPerSecond; | ||
62 | } | ||
63 | |||
64 | |||
65 | //! Gets the frame count of the animated mesh. | ||
66 | /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. | ||
67 | The actual speed is set in the scene node the mesh is instantiated in.*/ | ||
68 | void CSkinnedMesh::setAnimationSpeed(f32 fps) | ||
69 | { | ||
70 | FramesPerSecond=fps; | ||
71 | } | ||
72 | |||
73 | |||
74 | //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. | ||
75 | IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) | ||
76 | { | ||
77 | //animate(frame,startFrameLoop, endFrameLoop); | ||
78 | if (frame==-1) | ||
79 | return this; | ||
80 | |||
81 | animateMesh((f32)frame, 1.0f); | ||
82 | skinMesh(); | ||
83 | return this; | ||
84 | } | ||
85 | |||
86 | |||
87 | //-------------------------------------------------------------------------- | ||
88 | // Keyframe Animation | ||
89 | //-------------------------------------------------------------------------- | ||
90 | |||
91 | |||
92 | //! Animates this mesh's joints based on frame input | ||
93 | //! blend: {0-old position, 1-New position} | ||
94 | void CSkinnedMesh::animateMesh(f32 frame, f32 blend) | ||
95 | { | ||
96 | if (!HasAnimation || LastAnimatedFrame==frame) | ||
97 | return; | ||
98 | |||
99 | LastAnimatedFrame=frame; | ||
100 | SkinnedLastFrame=false; | ||
101 | |||
102 | if (blend<=0.f) | ||
103 | return; //No need to animate | ||
104 | |||
105 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
106 | { | ||
107 | //The joints can be animated here with no input from their | ||
108 | //parents, but for setAnimationMode extra checks are needed | ||
109 | //to their parents | ||
110 | SJoint *joint = AllJoints[i]; | ||
111 | |||
112 | const core::vector3df oldPosition = joint->Animatedposition; | ||
113 | const core::vector3df oldScale = joint->Animatedscale; | ||
114 | const core::quaternion oldRotation = joint->Animatedrotation; | ||
115 | |||
116 | core::vector3df position = oldPosition; | ||
117 | core::vector3df scale = oldScale; | ||
118 | core::quaternion rotation = oldRotation; | ||
119 | |||
120 | getFrameData(frame, joint, | ||
121 | position, joint->positionHint, | ||
122 | scale, joint->scaleHint, | ||
123 | rotation, joint->rotationHint); | ||
124 | |||
125 | if (blend==1.0f) | ||
126 | { | ||
127 | //No blending needed | ||
128 | joint->Animatedposition = position; | ||
129 | joint->Animatedscale = scale; | ||
130 | joint->Animatedrotation = rotation; | ||
131 | } | ||
132 | else | ||
133 | { | ||
134 | //Blend animation | ||
135 | joint->Animatedposition = core::lerp(oldPosition, position, blend); | ||
136 | joint->Animatedscale = core::lerp(oldScale, scale, blend); | ||
137 | joint->Animatedrotation.slerp(oldRotation, rotation, blend); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | //Note: | ||
142 | //LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for | ||
143 | //one render (to play two animations at the same time) LocalAnimatedMatrix only needs to be built once. | ||
144 | //a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move | ||
145 | |||
146 | //---------------- | ||
147 | // Temp! | ||
148 | buildAllLocalAnimatedMatrices(); | ||
149 | //----------------- | ||
150 | |||
151 | updateBoundingBox(); | ||
152 | } | ||
153 | |||
154 | |||
155 | void CSkinnedMesh::buildAllLocalAnimatedMatrices() | ||
156 | { | ||
157 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
158 | { | ||
159 | SJoint *joint = AllJoints[i]; | ||
160 | |||
161 | //Could be faster: | ||
162 | |||
163 | if (joint->UseAnimationFrom && | ||
164 | (joint->UseAnimationFrom->PositionKeys.size() || | ||
165 | joint->UseAnimationFrom->ScaleKeys.size() || | ||
166 | joint->UseAnimationFrom->RotationKeys.size() )) | ||
167 | { | ||
168 | joint->GlobalSkinningSpace=false; | ||
169 | |||
170 | // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. | ||
171 | // Not tested so far if this was correct or wrong before quaternion fix! | ||
172 | joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix); | ||
173 | |||
174 | // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() --- | ||
175 | f32 *m1 = joint->LocalAnimatedMatrix.pointer(); | ||
176 | core::vector3df &Pos = joint->Animatedposition; | ||
177 | m1[0] += Pos.X*m1[3]; | ||
178 | m1[1] += Pos.Y*m1[3]; | ||
179 | m1[2] += Pos.Z*m1[3]; | ||
180 | m1[4] += Pos.X*m1[7]; | ||
181 | m1[5] += Pos.Y*m1[7]; | ||
182 | m1[6] += Pos.Z*m1[7]; | ||
183 | m1[8] += Pos.X*m1[11]; | ||
184 | m1[9] += Pos.Y*m1[11]; | ||
185 | m1[10] += Pos.Z*m1[11]; | ||
186 | m1[12] += Pos.X*m1[15]; | ||
187 | m1[13] += Pos.Y*m1[15]; | ||
188 | m1[14] += Pos.Z*m1[15]; | ||
189 | // ----------------------------------- | ||
190 | |||
191 | if (joint->ScaleKeys.size()) | ||
192 | { | ||
193 | /* | ||
194 | core::matrix4 scaleMatrix; | ||
195 | scaleMatrix.setScale(joint->Animatedscale); | ||
196 | joint->LocalAnimatedMatrix *= scaleMatrix; | ||
197 | */ | ||
198 | |||
199 | // -------- joint->LocalAnimatedMatrix *= scaleMatrix ----------------- | ||
200 | core::matrix4& mat = joint->LocalAnimatedMatrix; | ||
201 | mat[0] *= joint->Animatedscale.X; | ||
202 | mat[1] *= joint->Animatedscale.X; | ||
203 | mat[2] *= joint->Animatedscale.X; | ||
204 | mat[3] *= joint->Animatedscale.X; | ||
205 | mat[4] *= joint->Animatedscale.Y; | ||
206 | mat[5] *= joint->Animatedscale.Y; | ||
207 | mat[6] *= joint->Animatedscale.Y; | ||
208 | mat[7] *= joint->Animatedscale.Y; | ||
209 | mat[8] *= joint->Animatedscale.Z; | ||
210 | mat[9] *= joint->Animatedscale.Z; | ||
211 | mat[10] *= joint->Animatedscale.Z; | ||
212 | mat[11] *= joint->Animatedscale.Z; | ||
213 | // ----------------------------------- | ||
214 | } | ||
215 | } | ||
216 | else | ||
217 | { | ||
218 | joint->LocalAnimatedMatrix=joint->LocalMatrix; | ||
219 | } | ||
220 | } | ||
221 | SkinnedLastFrame=false; | ||
222 | } | ||
223 | |||
224 | |||
225 | void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) | ||
226 | { | ||
227 | if (!joint) | ||
228 | { | ||
229 | for (u32 i=0; i<RootJoints.size(); ++i) | ||
230 | buildAllGlobalAnimatedMatrices(RootJoints[i], 0); | ||
231 | return; | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | // Find global matrix... | ||
236 | if (!parentJoint || joint->GlobalSkinningSpace) | ||
237 | joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix; | ||
238 | else | ||
239 | joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix; | ||
240 | } | ||
241 | |||
242 | for (u32 j=0; j<joint->Children.size(); ++j) | ||
243 | buildAllGlobalAnimatedMatrices(joint->Children[j], joint); | ||
244 | } | ||
245 | |||
246 | |||
247 | void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint, | ||
248 | core::vector3df &position, s32 &positionHint, | ||
249 | core::vector3df &scale, s32 &scaleHint, | ||
250 | core::quaternion &rotation, s32 &rotationHint) | ||
251 | { | ||
252 | s32 foundPositionIndex = -1; | ||
253 | s32 foundScaleIndex = -1; | ||
254 | s32 foundRotationIndex = -1; | ||
255 | |||
256 | if (joint->UseAnimationFrom) | ||
257 | { | ||
258 | const core::array<SPositionKey> &PositionKeys=joint->UseAnimationFrom->PositionKeys; | ||
259 | const core::array<SScaleKey> &ScaleKeys=joint->UseAnimationFrom->ScaleKeys; | ||
260 | const core::array<SRotationKey> &RotationKeys=joint->UseAnimationFrom->RotationKeys; | ||
261 | |||
262 | if (PositionKeys.size()) | ||
263 | { | ||
264 | foundPositionIndex = -1; | ||
265 | |||
266 | //Test the Hints... | ||
267 | if (positionHint>=0 && (u32)positionHint < PositionKeys.size()) | ||
268 | { | ||
269 | //check this hint | ||
270 | if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame<frame ) | ||
271 | foundPositionIndex=positionHint; | ||
272 | else if (positionHint+1 < (s32)PositionKeys.size()) | ||
273 | { | ||
274 | //check the next index | ||
275 | if ( PositionKeys[positionHint+1].frame>=frame && | ||
276 | PositionKeys[positionHint+0].frame<frame) | ||
277 | { | ||
278 | positionHint++; | ||
279 | foundPositionIndex=positionHint; | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | //The hint test failed, do a full scan... | ||
285 | if (foundPositionIndex==-1) | ||
286 | { | ||
287 | for (u32 i=0; i<PositionKeys.size(); ++i) | ||
288 | { | ||
289 | if (PositionKeys[i].frame >= frame) //Keys should to be sorted by frame | ||
290 | { | ||
291 | foundPositionIndex=i; | ||
292 | positionHint=i; | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | |||
298 | //Do interpolation... | ||
299 | if (foundPositionIndex!=-1) | ||
300 | { | ||
301 | if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0) | ||
302 | { | ||
303 | position = PositionKeys[foundPositionIndex].position; | ||
304 | } | ||
305 | else if (InterpolationMode==EIM_LINEAR) | ||
306 | { | ||
307 | const SPositionKey& KeyA = PositionKeys[foundPositionIndex]; | ||
308 | const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1]; | ||
309 | |||
310 | const f32 fd1 = frame - KeyA.frame; | ||
311 | const f32 fd2 = KeyB.frame - frame; | ||
312 | position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | //------------------------------------------------------------ | ||
318 | |||
319 | if (ScaleKeys.size()) | ||
320 | { | ||
321 | foundScaleIndex = -1; | ||
322 | |||
323 | //Test the Hints... | ||
324 | if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size()) | ||
325 | { | ||
326 | //check this hint | ||
327 | if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame<frame ) | ||
328 | foundScaleIndex=scaleHint; | ||
329 | else if (scaleHint+1 < (s32)ScaleKeys.size()) | ||
330 | { | ||
331 | //check the next index | ||
332 | if ( ScaleKeys[scaleHint+1].frame>=frame && | ||
333 | ScaleKeys[scaleHint+0].frame<frame) | ||
334 | { | ||
335 | scaleHint++; | ||
336 | foundScaleIndex=scaleHint; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | |||
342 | //The hint test failed, do a full scan... | ||
343 | if (foundScaleIndex==-1) | ||
344 | { | ||
345 | for (u32 i=0; i<ScaleKeys.size(); ++i) | ||
346 | { | ||
347 | if (ScaleKeys[i].frame >= frame) //Keys should to be sorted by frame | ||
348 | { | ||
349 | foundScaleIndex=i; | ||
350 | scaleHint=i; | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | |||
356 | //Do interpolation... | ||
357 | if (foundScaleIndex!=-1) | ||
358 | { | ||
359 | if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0) | ||
360 | { | ||
361 | scale = ScaleKeys[foundScaleIndex].scale; | ||
362 | } | ||
363 | else if (InterpolationMode==EIM_LINEAR) | ||
364 | { | ||
365 | const SScaleKey& KeyA = ScaleKeys[foundScaleIndex]; | ||
366 | const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1]; | ||
367 | |||
368 | const f32 fd1 = frame - KeyA.frame; | ||
369 | const f32 fd2 = KeyB.frame - frame; | ||
370 | scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale; | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | //------------------------------------------------------------- | ||
376 | |||
377 | if (RotationKeys.size()) | ||
378 | { | ||
379 | foundRotationIndex = -1; | ||
380 | |||
381 | //Test the Hints... | ||
382 | if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size()) | ||
383 | { | ||
384 | //check this hint | ||
385 | if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame<frame ) | ||
386 | foundRotationIndex=rotationHint; | ||
387 | else if (rotationHint+1 < (s32)RotationKeys.size()) | ||
388 | { | ||
389 | //check the next index | ||
390 | if ( RotationKeys[rotationHint+1].frame>=frame && | ||
391 | RotationKeys[rotationHint+0].frame<frame) | ||
392 | { | ||
393 | rotationHint++; | ||
394 | foundRotationIndex=rotationHint; | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | |||
399 | |||
400 | //The hint test failed, do a full scan... | ||
401 | if (foundRotationIndex==-1) | ||
402 | { | ||
403 | for (u32 i=0; i<RotationKeys.size(); ++i) | ||
404 | { | ||
405 | if (RotationKeys[i].frame >= frame) //Keys should be sorted by frame | ||
406 | { | ||
407 | foundRotationIndex=i; | ||
408 | rotationHint=i; | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | //Do interpolation... | ||
415 | if (foundRotationIndex!=-1) | ||
416 | { | ||
417 | if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0) | ||
418 | { | ||
419 | rotation = RotationKeys[foundRotationIndex].rotation; | ||
420 | } | ||
421 | else if (InterpolationMode==EIM_LINEAR) | ||
422 | { | ||
423 | const SRotationKey& KeyA = RotationKeys[foundRotationIndex]; | ||
424 | const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1]; | ||
425 | |||
426 | const f32 fd1 = frame - KeyA.frame; | ||
427 | const f32 fd2 = KeyB.frame - frame; | ||
428 | const f32 t = fd1/(fd1+fd2); | ||
429 | |||
430 | /* | ||
431 | f32 t = 0; | ||
432 | if (KeyA.frame!=KeyB.frame) | ||
433 | t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); | ||
434 | */ | ||
435 | |||
436 | rotation.slerp(KeyA.rotation, KeyB.rotation, t); | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | //-------------------------------------------------------------------------- | ||
444 | // Software Skinning | ||
445 | //-------------------------------------------------------------------------- | ||
446 | |||
447 | //! Preforms a software skin on this mesh based of joint positions | ||
448 | void CSkinnedMesh::skinMesh() | ||
449 | { | ||
450 | if (!HasAnimation || SkinnedLastFrame) | ||
451 | return; | ||
452 | |||
453 | //---------------- | ||
454 | // This is marked as "Temp!". A shiny dubloon to whomever can tell me why. | ||
455 | buildAllGlobalAnimatedMatrices(); | ||
456 | //----------------- | ||
457 | |||
458 | SkinnedLastFrame=true; | ||
459 | if (!HardwareSkinning) | ||
460 | { | ||
461 | //Software skin.... | ||
462 | u32 i; | ||
463 | |||
464 | //rigid animation | ||
465 | for (i=0; i<AllJoints.size(); ++i) | ||
466 | { | ||
467 | for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j) | ||
468 | { | ||
469 | SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; | ||
470 | Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | //clear skinning helper array | ||
475 | for (i=0; i<Vertices_Moved.size(); ++i) | ||
476 | for (u32 j=0; j<Vertices_Moved[i].size(); ++j) | ||
477 | Vertices_Moved[i][j]=false; | ||
478 | |||
479 | //skin starting with the root joints | ||
480 | for (i=0; i<RootJoints.size(); ++i) | ||
481 | skinJoint(RootJoints[i], 0); | ||
482 | |||
483 | for (i=0; i<SkinningBuffers->size(); ++i) | ||
484 | (*SkinningBuffers)[i]->setDirty(EBT_VERTEX); | ||
485 | } | ||
486 | updateBoundingBox(); | ||
487 | } | ||
488 | |||
489 | |||
490 | void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) | ||
491 | { | ||
492 | if (joint->Weights.size()) | ||
493 | { | ||
494 | //Find this joints pull on vertices... | ||
495 | core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); | ||
496 | jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); | ||
497 | |||
498 | core::vector3df thisVertexMove, thisNormalMove; | ||
499 | |||
500 | core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers; | ||
501 | |||
502 | //Skin Vertices Positions and Normals... | ||
503 | for (u32 i=0; i<joint->Weights.size(); ++i) | ||
504 | { | ||
505 | SWeight& weight = joint->Weights[i]; | ||
506 | |||
507 | // Pull this vertex... | ||
508 | jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); | ||
509 | |||
510 | if (AnimateNormals) | ||
511 | jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); | ||
512 | |||
513 | if (! (*(weight.Moved)) ) | ||
514 | { | ||
515 | *(weight.Moved) = true; | ||
516 | |||
517 | buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength; | ||
518 | |||
519 | if (AnimateNormals) | ||
520 | buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength; | ||
521 | |||
522 | //*(weight._Pos) = thisVertexMove * weight.strength; | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength; | ||
527 | |||
528 | if (AnimateNormals) | ||
529 | buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength; | ||
530 | |||
531 | //*(weight._Pos) += thisVertexMove * weight.strength; | ||
532 | } | ||
533 | |||
534 | buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated(); | ||
535 | } | ||
536 | } | ||
537 | |||
538 | //Skin all children | ||
539 | for (u32 j=0; j<joint->Children.size(); ++j) | ||
540 | skinJoint(joint->Children[j], joint); | ||
541 | } | ||
542 | |||
543 | |||
544 | E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const | ||
545 | { | ||
546 | return EAMT_SKINNED; | ||
547 | } | ||
548 | |||
549 | |||
550 | //! Gets joint count. | ||
551 | u32 CSkinnedMesh::getJointCount() const | ||
552 | { | ||
553 | return AllJoints.size(); | ||
554 | } | ||
555 | |||
556 | |||
557 | //! Gets the name of a joint. | ||
558 | const c8* CSkinnedMesh::getJointName(u32 number) const | ||
559 | { | ||
560 | if (number >= AllJoints.size()) | ||
561 | return 0; | ||
562 | return AllJoints[number]->Name.c_str(); | ||
563 | } | ||
564 | |||
565 | |||
566 | //! Gets a joint number from its name | ||
567 | s32 CSkinnedMesh::getJointNumber(const c8* name) const | ||
568 | { | ||
569 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
570 | { | ||
571 | if (AllJoints[i]->Name == name) | ||
572 | return i; | ||
573 | } | ||
574 | |||
575 | return -1; | ||
576 | } | ||
577 | |||
578 | |||
579 | //! returns amount of mesh buffers. | ||
580 | u32 CSkinnedMesh::getMeshBufferCount() const | ||
581 | { | ||
582 | return LocalBuffers.size(); | ||
583 | } | ||
584 | |||
585 | |||
586 | //! returns pointer to a mesh buffer | ||
587 | IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const | ||
588 | { | ||
589 | if (nr < LocalBuffers.size()) | ||
590 | return LocalBuffers[nr]; | ||
591 | else | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | |||
596 | //! Returns pointer to a mesh buffer which fits a material | ||
597 | IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const | ||
598 | { | ||
599 | for (u32 i=0; i<LocalBuffers.size(); ++i) | ||
600 | { | ||
601 | if (LocalBuffers[i]->getMaterial() == material) | ||
602 | return LocalBuffers[i]; | ||
603 | } | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | |||
608 | //! returns an axis aligned bounding box | ||
609 | const core::aabbox3d<f32>& CSkinnedMesh::getBoundingBox() const | ||
610 | { | ||
611 | return BoundingBox; | ||
612 | } | ||
613 | |||
614 | |||
615 | //! set user axis aligned bounding box | ||
616 | void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box) | ||
617 | { | ||
618 | BoundingBox = box; | ||
619 | } | ||
620 | |||
621 | |||
622 | //! sets a flag of all contained materials to a new value | ||
623 | void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) | ||
624 | { | ||
625 | for (u32 i=0; i<LocalBuffers.size(); ++i) | ||
626 | LocalBuffers[i]->Material.setFlag(flag,newvalue); | ||
627 | } | ||
628 | |||
629 | |||
630 | //! set the hardware mapping hint, for driver | ||
631 | void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, | ||
632 | E_BUFFER_TYPE buffer) | ||
633 | { | ||
634 | for (u32 i=0; i<LocalBuffers.size(); ++i) | ||
635 | LocalBuffers[i]->setHardwareMappingHint(newMappingHint, buffer); | ||
636 | } | ||
637 | |||
638 | |||
639 | //! flags the meshbuffer as changed, reloads hardware buffers | ||
640 | void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer) | ||
641 | { | ||
642 | for (u32 i=0; i<LocalBuffers.size(); ++i) | ||
643 | LocalBuffers[i]->setDirty(buffer); | ||
644 | } | ||
645 | |||
646 | |||
647 | //! uses animation from another mesh | ||
648 | bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh) | ||
649 | { | ||
650 | bool unmatched=false; | ||
651 | |||
652 | for(u32 i=0;i<AllJoints.size();++i) | ||
653 | { | ||
654 | SJoint *joint=AllJoints[i]; | ||
655 | joint->UseAnimationFrom=0; | ||
656 | |||
657 | if (joint->Name=="") | ||
658 | unmatched=true; | ||
659 | else | ||
660 | { | ||
661 | for(u32 j=0;j<mesh->getAllJoints().size();++j) | ||
662 | { | ||
663 | SJoint *otherJoint=mesh->getAllJoints()[j]; | ||
664 | if (joint->Name==otherJoint->Name) | ||
665 | { | ||
666 | joint->UseAnimationFrom=otherJoint; | ||
667 | } | ||
668 | } | ||
669 | if (!joint->UseAnimationFrom) | ||
670 | unmatched=true; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | checkForAnimation(); | ||
675 | |||
676 | return !unmatched; | ||
677 | } | ||
678 | |||
679 | |||
680 | //!Update Normals when Animating | ||
681 | //!False= Don't animate them, faster | ||
682 | //!True= Update normals (default) | ||
683 | void CSkinnedMesh::updateNormalsWhenAnimating(bool on) | ||
684 | { | ||
685 | AnimateNormals = on; | ||
686 | } | ||
687 | |||
688 | |||
689 | //!Sets Interpolation Mode | ||
690 | void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) | ||
691 | { | ||
692 | InterpolationMode = mode; | ||
693 | } | ||
694 | |||
695 | |||
696 | core::array<scene::SSkinMeshBuffer*> &CSkinnedMesh::getMeshBuffers() | ||
697 | { | ||
698 | return LocalBuffers; | ||
699 | } | ||
700 | |||
701 | |||
702 | core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() | ||
703 | { | ||
704 | return AllJoints; | ||
705 | } | ||
706 | |||
707 | |||
708 | const core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() const | ||
709 | { | ||
710 | return AllJoints; | ||
711 | } | ||
712 | |||
713 | |||
714 | //! (This feature is not implementated in irrlicht yet) | ||
715 | bool CSkinnedMesh::setHardwareSkinning(bool on) | ||
716 | { | ||
717 | if (HardwareSkinning!=on) | ||
718 | { | ||
719 | if (on) | ||
720 | { | ||
721 | |||
722 | //set mesh to static pose... | ||
723 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
724 | { | ||
725 | SJoint *joint=AllJoints[i]; | ||
726 | for (u32 j=0; j<joint->Weights.size(); ++j) | ||
727 | { | ||
728 | const u16 buffer_id=joint->Weights[j].buffer_id; | ||
729 | const u32 vertex_id=joint->Weights[j].vertex_id; | ||
730 | LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; | ||
731 | LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; | ||
732 | LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated(); | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | |||
737 | HardwareSkinning=on; | ||
738 | } | ||
739 | return HardwareSkinning; | ||
740 | } | ||
741 | |||
742 | |||
743 | void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint,SJoint *parentJoint) | ||
744 | { | ||
745 | if (!joint && parentJoint) // bit of protection from endless loops | ||
746 | return; | ||
747 | |||
748 | //Go through the root bones | ||
749 | if (!joint) | ||
750 | { | ||
751 | for (u32 i=0; i<RootJoints.size(); ++i) | ||
752 | calculateGlobalMatrices(RootJoints[i],0); | ||
753 | return; | ||
754 | } | ||
755 | |||
756 | if (!parentJoint) | ||
757 | joint->GlobalMatrix = joint->LocalMatrix; | ||
758 | else | ||
759 | joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix; | ||
760 | |||
761 | joint->LocalAnimatedMatrix=joint->LocalMatrix; | ||
762 | joint->GlobalAnimatedMatrix=joint->GlobalMatrix; | ||
763 | |||
764 | if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated | ||
765 | { | ||
766 | joint->GlobalInversedMatrix = joint->GlobalMatrix; | ||
767 | joint->GlobalInversedMatrix.makeInverse(); // slow | ||
768 | } | ||
769 | |||
770 | for (u32 j=0; j<joint->Children.size(); ++j) | ||
771 | calculateGlobalMatrices(joint->Children[j],joint); | ||
772 | SkinnedLastFrame=false; | ||
773 | } | ||
774 | |||
775 | |||
776 | void CSkinnedMesh::checkForAnimation() | ||
777 | { | ||
778 | u32 i,j; | ||
779 | //Check for animation... | ||
780 | HasAnimation = false; | ||
781 | for(i=0;i<AllJoints.size();++i) | ||
782 | { | ||
783 | if (AllJoints[i]->UseAnimationFrom) | ||
784 | { | ||
785 | if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || | ||
786 | AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || | ||
787 | AllJoints[i]->UseAnimationFrom->RotationKeys.size() ) | ||
788 | { | ||
789 | HasAnimation = true; | ||
790 | } | ||
791 | } | ||
792 | } | ||
793 | |||
794 | //meshes with weights, are still counted as animated for ragdolls, etc | ||
795 | if (!HasAnimation) | ||
796 | { | ||
797 | for(i=0;i<AllJoints.size();++i) | ||
798 | { | ||
799 | if (AllJoints[i]->Weights.size()) | ||
800 | HasAnimation = true; | ||
801 | } | ||
802 | } | ||
803 | |||
804 | if (HasAnimation) | ||
805 | { | ||
806 | //--- Find the length of the animation --- | ||
807 | AnimationFrames=0; | ||
808 | for(i=0;i<AllJoints.size();++i) | ||
809 | { | ||
810 | if (AllJoints[i]->UseAnimationFrom) | ||
811 | { | ||
812 | if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) | ||
813 | if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames) | ||
814 | AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; | ||
815 | |||
816 | if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) | ||
817 | if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames) | ||
818 | AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; | ||
819 | |||
820 | if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) | ||
821 | if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames) | ||
822 | AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | |||
827 | if (HasAnimation && !PreparedForSkinning) | ||
828 | { | ||
829 | PreparedForSkinning=true; | ||
830 | |||
831 | //check for bugs: | ||
832 | for(i=0; i < AllJoints.size(); ++i) | ||
833 | { | ||
834 | SJoint *joint = AllJoints[i]; | ||
835 | for (j=0; j<joint->Weights.size(); ++j) | ||
836 | { | ||
837 | const u16 buffer_id=joint->Weights[j].buffer_id; | ||
838 | const u32 vertex_id=joint->Weights[j].vertex_id; | ||
839 | |||
840 | //check for invalid ids | ||
841 | if (buffer_id>=LocalBuffers.size()) | ||
842 | { | ||
843 | os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING); | ||
844 | joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; | ||
845 | } | ||
846 | else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount()) | ||
847 | { | ||
848 | os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING); | ||
849 | joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0; | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | |||
854 | //An array used in skinning | ||
855 | |||
856 | for (i=0; i<Vertices_Moved.size(); ++i) | ||
857 | for (j=0; j<Vertices_Moved[i].size(); ++j) | ||
858 | Vertices_Moved[i][j] = false; | ||
859 | |||
860 | // For skinning: cache weight values for speed | ||
861 | |||
862 | for (i=0; i<AllJoints.size(); ++i) | ||
863 | { | ||
864 | SJoint *joint = AllJoints[i]; | ||
865 | for (j=0; j<joint->Weights.size(); ++j) | ||
866 | { | ||
867 | const u16 buffer_id=joint->Weights[j].buffer_id; | ||
868 | const u32 vertex_id=joint->Weights[j].vertex_id; | ||
869 | |||
870 | joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id]; | ||
871 | joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; | ||
872 | joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; | ||
873 | |||
874 | //joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | // normalize weights | ||
879 | normalizeWeights(); | ||
880 | } | ||
881 | SkinnedLastFrame=false; | ||
882 | } | ||
883 | |||
884 | |||
885 | //! called by loader after populating with mesh and bone data | ||
886 | void CSkinnedMesh::finalize() | ||
887 | { | ||
888 | u32 i; | ||
889 | |||
890 | // Make sure we recalc the next frame | ||
891 | LastAnimatedFrame=-1; | ||
892 | SkinnedLastFrame=false; | ||
893 | |||
894 | //calculate bounding box | ||
895 | for (i=0; i<LocalBuffers.size(); ++i) | ||
896 | { | ||
897 | LocalBuffers[i]->recalculateBoundingBox(); | ||
898 | } | ||
899 | |||
900 | if (AllJoints.size() || RootJoints.size()) | ||
901 | { | ||
902 | // populate AllJoints or RootJoints, depending on which is empty | ||
903 | if (!RootJoints.size()) | ||
904 | { | ||
905 | |||
906 | for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx) | ||
907 | { | ||
908 | |||
909 | bool foundParent=false; | ||
910 | for(i=0; i < AllJoints.size(); ++i) | ||
911 | { | ||
912 | for(u32 n=0; n < AllJoints[i]->Children.size(); ++n) | ||
913 | { | ||
914 | if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) | ||
915 | foundParent=true; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | if (!foundParent) | ||
920 | RootJoints.push_back(AllJoints[CheckingIdx]); | ||
921 | } | ||
922 | } | ||
923 | else | ||
924 | { | ||
925 | AllJoints=RootJoints; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | for(i=0; i < AllJoints.size(); ++i) | ||
930 | { | ||
931 | AllJoints[i]->UseAnimationFrom=AllJoints[i]; | ||
932 | } | ||
933 | |||
934 | //Set array sizes... | ||
935 | |||
936 | for (i=0; i<LocalBuffers.size(); ++i) | ||
937 | { | ||
938 | Vertices_Moved.push_back( core::array<bool>() ); | ||
939 | Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); | ||
940 | } | ||
941 | |||
942 | //Todo: optimise keys here... | ||
943 | |||
944 | checkForAnimation(); | ||
945 | |||
946 | if (HasAnimation) | ||
947 | { | ||
948 | //--- optimize and check keyframes --- | ||
949 | for(i=0;i<AllJoints.size();++i) | ||
950 | { | ||
951 | core::array<SPositionKey> &PositionKeys =AllJoints[i]->PositionKeys; | ||
952 | core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys; | ||
953 | core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys; | ||
954 | |||
955 | if (PositionKeys.size()>2) | ||
956 | { | ||
957 | for(u32 j=0;j<PositionKeys.size()-2;++j) | ||
958 | { | ||
959 | if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position) | ||
960 | { | ||
961 | PositionKeys.erase(j+1); //the middle key is unneeded | ||
962 | --j; | ||
963 | } | ||
964 | } | ||
965 | } | ||
966 | |||
967 | if (PositionKeys.size()>1) | ||
968 | { | ||
969 | for(u32 j=0;j<PositionKeys.size()-1;++j) | ||
970 | { | ||
971 | if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems | ||
972 | { | ||
973 | PositionKeys.erase(j+1); | ||
974 | --j; | ||
975 | } | ||
976 | } | ||
977 | } | ||
978 | |||
979 | if (ScaleKeys.size()>2) | ||
980 | { | ||
981 | for(u32 j=0;j<ScaleKeys.size()-2;++j) | ||
982 | { | ||
983 | if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale) | ||
984 | { | ||
985 | ScaleKeys.erase(j+1); //the middle key is unneeded | ||
986 | --j; | ||
987 | } | ||
988 | } | ||
989 | } | ||
990 | |||
991 | if (ScaleKeys.size()>1) | ||
992 | { | ||
993 | for(u32 j=0;j<ScaleKeys.size()-1;++j) | ||
994 | { | ||
995 | if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems | ||
996 | { | ||
997 | ScaleKeys.erase(j+1); | ||
998 | --j; | ||
999 | } | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | if (RotationKeys.size()>2) | ||
1004 | { | ||
1005 | for(u32 j=0;j<RotationKeys.size()-2;++j) | ||
1006 | { | ||
1007 | if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation) | ||
1008 | { | ||
1009 | RotationKeys.erase(j+1); //the middle key is unneeded | ||
1010 | --j; | ||
1011 | } | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | if (RotationKeys.size()>1) | ||
1016 | { | ||
1017 | for(u32 j=0;j<RotationKeys.size()-1;++j) | ||
1018 | { | ||
1019 | if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems | ||
1020 | { | ||
1021 | RotationKeys.erase(j+1); | ||
1022 | --j; | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | //Fill empty keyframe areas | ||
1029 | if (PositionKeys.size()) | ||
1030 | { | ||
1031 | SPositionKey *Key; | ||
1032 | Key=&PositionKeys[0];//getFirst | ||
1033 | if (Key->frame!=0) | ||
1034 | { | ||
1035 | PositionKeys.push_front(*Key); | ||
1036 | Key=&PositionKeys[0];//getFirst | ||
1037 | Key->frame=0; | ||
1038 | } | ||
1039 | |||
1040 | Key=&PositionKeys.getLast(); | ||
1041 | if (Key->frame!=AnimationFrames) | ||
1042 | { | ||
1043 | PositionKeys.push_back(*Key); | ||
1044 | Key=&PositionKeys.getLast(); | ||
1045 | Key->frame=AnimationFrames; | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | if (ScaleKeys.size()) | ||
1050 | { | ||
1051 | SScaleKey *Key; | ||
1052 | Key=&ScaleKeys[0];//getFirst | ||
1053 | if (Key->frame!=0) | ||
1054 | { | ||
1055 | ScaleKeys.push_front(*Key); | ||
1056 | Key=&ScaleKeys[0];//getFirst | ||
1057 | Key->frame=0; | ||
1058 | } | ||
1059 | |||
1060 | Key=&ScaleKeys.getLast(); | ||
1061 | if (Key->frame!=AnimationFrames) | ||
1062 | { | ||
1063 | ScaleKeys.push_back(*Key); | ||
1064 | Key=&ScaleKeys.getLast(); | ||
1065 | Key->frame=AnimationFrames; | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | if (RotationKeys.size()) | ||
1070 | { | ||
1071 | SRotationKey *Key; | ||
1072 | Key=&RotationKeys[0];//getFirst | ||
1073 | if (Key->frame!=0) | ||
1074 | { | ||
1075 | RotationKeys.push_front(*Key); | ||
1076 | Key=&RotationKeys[0];//getFirst | ||
1077 | Key->frame=0; | ||
1078 | } | ||
1079 | |||
1080 | Key=&RotationKeys.getLast(); | ||
1081 | if (Key->frame!=AnimationFrames) | ||
1082 | { | ||
1083 | RotationKeys.push_back(*Key); | ||
1084 | Key=&RotationKeys.getLast(); | ||
1085 | Key->frame=AnimationFrames; | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | } | ||
1090 | |||
1091 | //Needed for animation and skinning... | ||
1092 | |||
1093 | calculateGlobalMatrices(0,0); | ||
1094 | |||
1095 | //animateMesh(0, 1); | ||
1096 | //buildAllLocalAnimatedMatrices(); | ||
1097 | //buildAllGlobalAnimatedMatrices(); | ||
1098 | |||
1099 | //rigid animation for non animated meshes | ||
1100 | for (i=0; i<AllJoints.size(); ++i) | ||
1101 | { | ||
1102 | for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j) | ||
1103 | { | ||
1104 | SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ]; | ||
1105 | Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | //calculate bounding box | ||
1110 | if (LocalBuffers.empty()) | ||
1111 | BoundingBox.reset(0,0,0); | ||
1112 | else | ||
1113 | { | ||
1114 | irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox); | ||
1115 | LocalBuffers[0]->Transformation.transformBoxEx(bb); | ||
1116 | BoundingBox.reset(bb); | ||
1117 | |||
1118 | for (u32 j=1; j<LocalBuffers.size(); ++j) | ||
1119 | { | ||
1120 | bb = LocalBuffers[j]->BoundingBox; | ||
1121 | LocalBuffers[j]->Transformation.transformBoxEx(bb); | ||
1122 | |||
1123 | BoundingBox.addInternalBox(bb); | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | |||
1129 | void CSkinnedMesh::updateBoundingBox(void) | ||
1130 | { | ||
1131 | if(!SkinningBuffers) | ||
1132 | return; | ||
1133 | |||
1134 | core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers; | ||
1135 | BoundingBox.reset(0,0,0); | ||
1136 | |||
1137 | if (!buffer.empty()) | ||
1138 | { | ||
1139 | for (u32 j=0; j<buffer.size(); ++j) | ||
1140 | { | ||
1141 | buffer[j]->recalculateBoundingBox(); | ||
1142 | core::aabbox3df bb = buffer[j]->BoundingBox; | ||
1143 | buffer[j]->Transformation.transformBoxEx(bb); | ||
1144 | |||
1145 | BoundingBox.addInternalBox(bb); | ||
1146 | } | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | |||
1151 | scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer() | ||
1152 | { | ||
1153 | scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer(); | ||
1154 | LocalBuffers.push_back(buffer); | ||
1155 | return buffer; | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent) | ||
1160 | { | ||
1161 | SJoint *joint=new SJoint; | ||
1162 | |||
1163 | AllJoints.push_back(joint); | ||
1164 | if (!parent) | ||
1165 | { | ||
1166 | //Add root joints to array in finalize() | ||
1167 | } | ||
1168 | else | ||
1169 | { | ||
1170 | //Set parent (Be careful of the mesh loader also setting the parent) | ||
1171 | parent->Children.push_back(joint); | ||
1172 | } | ||
1173 | |||
1174 | return joint; | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint) | ||
1179 | { | ||
1180 | if (!joint) | ||
1181 | return 0; | ||
1182 | |||
1183 | joint->PositionKeys.push_back(SPositionKey()); | ||
1184 | return &joint->PositionKeys.getLast(); | ||
1185 | } | ||
1186 | |||
1187 | |||
1188 | CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint) | ||
1189 | { | ||
1190 | if (!joint) | ||
1191 | return 0; | ||
1192 | |||
1193 | joint->ScaleKeys.push_back(SScaleKey()); | ||
1194 | return &joint->ScaleKeys.getLast(); | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint) | ||
1199 | { | ||
1200 | if (!joint) | ||
1201 | return 0; | ||
1202 | |||
1203 | joint->RotationKeys.push_back(SRotationKey()); | ||
1204 | return &joint->RotationKeys.getLast(); | ||
1205 | } | ||
1206 | |||
1207 | |||
1208 | CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint) | ||
1209 | { | ||
1210 | if (!joint) | ||
1211 | return 0; | ||
1212 | |||
1213 | joint->Weights.push_back(SWeight()); | ||
1214 | return &joint->Weights.getLast(); | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | bool CSkinnedMesh::isStatic() | ||
1219 | { | ||
1220 | return !HasAnimation; | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | void CSkinnedMesh::normalizeWeights() | ||
1225 | { | ||
1226 | // note: unsure if weights ids are going to be used. | ||
1227 | |||
1228 | // Normalise the weights on bones.... | ||
1229 | |||
1230 | u32 i,j; | ||
1231 | core::array< core::array<f32> > verticesTotalWeight; | ||
1232 | |||
1233 | verticesTotalWeight.reallocate(LocalBuffers.size()); | ||
1234 | for (i=0; i<LocalBuffers.size(); ++i) | ||
1235 | { | ||
1236 | verticesTotalWeight.push_back(core::array<f32>()); | ||
1237 | verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); | ||
1238 | } | ||
1239 | |||
1240 | for (i=0; i<verticesTotalWeight.size(); ++i) | ||
1241 | for (j=0; j<verticesTotalWeight[i].size(); ++j) | ||
1242 | verticesTotalWeight[i][j] = 0; | ||
1243 | |||
1244 | for (i=0; i<AllJoints.size(); ++i) | ||
1245 | { | ||
1246 | SJoint *joint=AllJoints[i]; | ||
1247 | for (j=0; j<joint->Weights.size(); ++j) | ||
1248 | { | ||
1249 | if (joint->Weights[j].strength<=0)//Check for invalid weights | ||
1250 | { | ||
1251 | joint->Weights.erase(j); | ||
1252 | --j; | ||
1253 | } | ||
1254 | else | ||
1255 | { | ||
1256 | verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id] += joint->Weights[j].strength; | ||
1257 | } | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | for (i=0; i<AllJoints.size(); ++i) | ||
1262 | { | ||
1263 | SJoint *joint=AllJoints[i]; | ||
1264 | for (j=0; j< joint->Weights.size(); ++j) | ||
1265 | { | ||
1266 | const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id]; | ||
1267 | if (total != 0 && total != 1) | ||
1268 | joint->Weights[j].strength /= total; | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||
1272 | |||
1273 | |||
1274 | void CSkinnedMesh::recoverJointsFromMesh(core::array<IBoneSceneNode*> &jointChildSceneNodes) | ||
1275 | { | ||
1276 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
1277 | { | ||
1278 | IBoneSceneNode* node=jointChildSceneNodes[i]; | ||
1279 | SJoint *joint=AllJoints[i]; | ||
1280 | node->setPosition(joint->LocalAnimatedMatrix.getTranslation()); | ||
1281 | node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees()); | ||
1282 | node->setScale(joint->LocalAnimatedMatrix.getScale()); | ||
1283 | |||
1284 | node->positionHint=joint->positionHint; | ||
1285 | node->scaleHint=joint->scaleHint; | ||
1286 | node->rotationHint=joint->rotationHint; | ||
1287 | |||
1288 | node->updateAbsolutePosition(); | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | void CSkinnedMesh::transferJointsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes) | ||
1294 | { | ||
1295 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
1296 | { | ||
1297 | const IBoneSceneNode* const node=jointChildSceneNodes[i]; | ||
1298 | SJoint *joint=AllJoints[i]; | ||
1299 | |||
1300 | joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation()); | ||
1301 | joint->LocalAnimatedMatrix.setTranslation(node->getPosition()); | ||
1302 | joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale()); | ||
1303 | |||
1304 | joint->positionHint=node->positionHint; | ||
1305 | joint->scaleHint=node->scaleHint; | ||
1306 | joint->rotationHint=node->rotationHint; | ||
1307 | |||
1308 | joint->GlobalSkinningSpace=(node->getSkinningSpace()==EBSS_GLOBAL); | ||
1309 | } | ||
1310 | // Make sure we recalc the next frame | ||
1311 | LastAnimatedFrame=-1; | ||
1312 | SkinnedLastFrame=false; | ||
1313 | } | ||
1314 | |||
1315 | |||
1316 | void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes) | ||
1317 | { | ||
1318 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
1319 | { | ||
1320 | const IBoneSceneNode* const node=jointChildSceneNodes[i]; | ||
1321 | SJoint *joint=AllJoints[i]; | ||
1322 | |||
1323 | joint->positionHint=node->positionHint; | ||
1324 | joint->scaleHint=node->scaleHint; | ||
1325 | joint->rotationHint=node->rotationHint; | ||
1326 | } | ||
1327 | SkinnedLastFrame=false; | ||
1328 | } | ||
1329 | |||
1330 | |||
1331 | void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes, | ||
1332 | IAnimatedMeshSceneNode* node, ISceneManager* smgr) | ||
1333 | { | ||
1334 | //Create new joints | ||
1335 | for (u32 i=0; i<AllJoints.size(); ++i) | ||
1336 | { | ||
1337 | jointChildSceneNodes.push_back(new CBoneSceneNode(0, smgr, 0, i, AllJoints[i]->Name.c_str())); | ||
1338 | } | ||
1339 | |||
1340 | //Match up parents | ||
1341 | for (u32 i=0; i<jointChildSceneNodes.size(); ++i) | ||
1342 | { | ||
1343 | const SJoint* const joint=AllJoints[i]; //should be fine | ||
1344 | |||
1345 | s32 parentID=-1; | ||
1346 | |||
1347 | for (u32 j=0;(parentID==-1)&&(j<AllJoints.size());++j) | ||
1348 | { | ||
1349 | if (i!=j) | ||
1350 | { | ||
1351 | const SJoint* const parentTest=AllJoints[j]; | ||
1352 | for (u32 n=0; n<parentTest->Children.size(); ++n) | ||
1353 | { | ||
1354 | if (parentTest->Children[n]==joint) | ||
1355 | { | ||
1356 | parentID=j; | ||
1357 | break; | ||
1358 | } | ||
1359 | } | ||
1360 | } | ||
1361 | } | ||
1362 | |||
1363 | IBoneSceneNode* bone=jointChildSceneNodes[i]; | ||
1364 | if (parentID!=-1) | ||
1365 | bone->setParent(jointChildSceneNodes[parentID]); | ||
1366 | else | ||
1367 | bone->setParent(node); | ||
1368 | |||
1369 | bone->drop(); | ||
1370 | } | ||
1371 | SkinnedLastFrame=false; | ||
1372 | } | ||
1373 | |||
1374 | |||
1375 | void CSkinnedMesh::convertMeshToTangents() | ||
1376 | { | ||
1377 | // now calculate tangents | ||
1378 | for (u32 b=0; b < LocalBuffers.size(); ++b) | ||
1379 | { | ||
1380 | if (LocalBuffers[b]) | ||
1381 | { | ||
1382 | LocalBuffers[b]->convertToTangents(); | ||
1383 | |||
1384 | const s32 idxCnt = LocalBuffers[b]->getIndexCount(); | ||
1385 | |||
1386 | u16* idx = LocalBuffers[b]->getIndices(); | ||
1387 | video::S3DVertexTangents* v = | ||
1388 | (video::S3DVertexTangents*)LocalBuffers[b]->getVertices(); | ||
1389 | |||
1390 | for (s32 i=0; i<idxCnt; i+=3) | ||
1391 | { | ||
1392 | calculateTangents( | ||
1393 | v[idx[i+0]].Normal, | ||
1394 | v[idx[i+0]].Tangent, | ||
1395 | v[idx[i+0]].Binormal, | ||
1396 | v[idx[i+0]].Pos, | ||
1397 | v[idx[i+1]].Pos, | ||
1398 | v[idx[i+2]].Pos, | ||
1399 | v[idx[i+0]].TCoords, | ||
1400 | v[idx[i+1]].TCoords, | ||
1401 | v[idx[i+2]].TCoords); | ||
1402 | |||
1403 | calculateTangents( | ||
1404 | v[idx[i+1]].Normal, | ||
1405 | v[idx[i+1]].Tangent, | ||
1406 | v[idx[i+1]].Binormal, | ||
1407 | v[idx[i+1]].Pos, | ||
1408 | v[idx[i+2]].Pos, | ||
1409 | v[idx[i+0]].Pos, | ||
1410 | v[idx[i+1]].TCoords, | ||
1411 | v[idx[i+2]].TCoords, | ||
1412 | v[idx[i+0]].TCoords); | ||
1413 | |||
1414 | calculateTangents( | ||
1415 | v[idx[i+2]].Normal, | ||
1416 | v[idx[i+2]].Tangent, | ||
1417 | v[idx[i+2]].Binormal, | ||
1418 | v[idx[i+2]].Pos, | ||
1419 | v[idx[i+0]].Pos, | ||
1420 | v[idx[i+1]].Pos, | ||
1421 | v[idx[i+2]].TCoords, | ||
1422 | v[idx[i+0]].TCoords, | ||
1423 | v[idx[i+1]].TCoords); | ||
1424 | } | ||
1425 | } | ||
1426 | } | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | void CSkinnedMesh::calculateTangents( | ||
1431 | core::vector3df& normal, | ||
1432 | core::vector3df& tangent, | ||
1433 | core::vector3df& binormal, | ||
1434 | core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, // vertices | ||
1435 | core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3) // texture coords | ||
1436 | { | ||
1437 | core::vector3df v1 = vt1 - vt2; | ||
1438 | core::vector3df v2 = vt3 - vt1; | ||
1439 | normal = v2.crossProduct(v1); | ||
1440 | normal.normalize(); | ||
1441 | |||
1442 | // binormal | ||
1443 | |||
1444 | f32 deltaX1 = tc1.X - tc2.X; | ||
1445 | f32 deltaX2 = tc3.X - tc1.X; | ||
1446 | binormal = (v1 * deltaX2) - (v2 * deltaX1); | ||
1447 | binormal.normalize(); | ||
1448 | |||
1449 | // tangent | ||
1450 | |||
1451 | f32 deltaY1 = tc1.Y - tc2.Y; | ||
1452 | f32 deltaY2 = tc3.Y - tc1.Y; | ||
1453 | tangent = (v1 * deltaY2) - (v2 * deltaY1); | ||
1454 | tangent.normalize(); | ||
1455 | |||
1456 | // adjust | ||
1457 | |||
1458 | core::vector3df txb = tangent.crossProduct(binormal); | ||
1459 | if (txb.dotProduct(normal) < 0.0f) | ||
1460 | { | ||
1461 | tangent *= -1.0f; | ||
1462 | binormal *= -1.0f; | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | |||
1467 | } // end namespace scene | ||
1468 | } // end namespace irr | ||
1469 | |||
1470 | #endif // _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ | ||
1471 | |||