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