1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_SkeletonUpdater.cpp
4
5 Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain proprietary
8 information of Nintendo and/or its licensed developers and are protected by
9 national and international copyright laws. They may not be disclosed to third
10 parties or copied or duplicated in any form, in whole or in part, without the
11 prior written consent of Nintendo.
12
13 The content herein is highly confidential and should be handled accordingly.
14
15 $Revision: 31311 $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/gfx/gfx_SkeletonUpdater.h>
21 #include <nw/gfx/gfx_WorldMatrixUpdater.h>
22 #include <nw/gfx/gfx_BillboardUpdater.h>
23 #include <nw/gfx/gfx_Camera.h>
24 #include <nw/gfx/gfx_SkeletalModel.h>
25 #include <nw/gfx/gfx_Skeleton.h>
26 #include <nw/gfx/res/gfx_ResSkeleton.h>
27 #include <nw/ut/ut_Foreach.h>
28 #include <nw/dev.h>
29
30 namespace nw
31 {
32 namespace gfx
33 {
34
35 //----------------------------------------
36 SkeletonUpdater*
Create(os::IAllocator * allocator)37 SkeletonUpdater::Builder::Create(
38 os::IAllocator* allocator
39 )
40 {
41 NW_NULL_ASSERT(allocator);
42
43 void* updaterMemory = allocator->Alloc(sizeof(SkeletonUpdater));
44 NW_NULL_ASSERT(updaterMemory);
45
46 return new(updaterMemory) SkeletonUpdater(allocator);
47 }
48
49 //----------------------------------------
SkeletonUpdater(os::IAllocator * allocator)50 SkeletonUpdater::SkeletonUpdater(
51 os::IAllocator* allocator
52 )
53 : GfxObject(allocator)
54 {
55 }
56
57 //----------------------------------------
~SkeletonUpdater()58 SkeletonUpdater::~SkeletonUpdater()
59 {
60 }
61
62 //----------------------------------------
63 void
UpdateWorld(Skeleton * skeleton,const WorldMatrixUpdater & worldMatrixUpdater) const64 SkeletonUpdater::UpdateWorld(
65 Skeleton* skeleton,
66 const WorldMatrixUpdater& worldMatrixUpdater
67 ) const
68 {
69 NW_NULL_ASSERT(skeleton);
70
71 ResSkeleton resSkeleton = skeleton->GetResSkeleton();
72 NW_ASSERT(resSkeleton.IsValid());
73 bool isModelCoordinate = ut::CheckFlag(resSkeleton.GetFlags(), ResSkeletonData::FLAG_MODEL_COORDINATE);
74 Skeleton::TransformPose& pose = skeleton->LocalTransformPose();
75 Skeleton::TransformPose& worldPose = skeleton->WorldTransformPose();
76
77 int index = 0;
78 Skeleton::MatrixPose::MatrixRange range = skeleton->WorldMatrixPose().GetAllMatrices();
79 WorldMatrixUpdater::ScalingRule scalingRule = static_cast<WorldMatrixUpdater::ScalingRule>(resSkeleton.GetScalingRule());
80
81 if (scalingRule == WorldMatrixUpdater::SCALING_RULE_MAYA)
82 {
83 for (Skeleton::MatrixPose::MatrixArray::iterator matrix = range.first; matrix != range.second; ++matrix, ++index)
84 {
85 skeleton->PreCalculateMatrixSignal()(skeleton, index);
86
87 // CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED を 0 にしたときでもコールバックは呼ばれます。
88 if (pose.GetTransform(index)->IsEnabledFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED) )
89 {
90 ResBone bone = resSkeleton.GetBones(index);
91 int parentBoneIndex = bone.GetParentBoneIndex();
92 const CalculatedTransform* parentWorldTransform;
93 const CalculatedTransform* parentLocalTransform;
94
95 if (parentBoneIndex == -1)
96 {
97 if (isModelCoordinate)
98 {
99 parentWorldTransform = &CalculatedTransform::Identity();
100 parentLocalTransform = &CalculatedTransform::Identity();
101 }
102 else
103 {
104 parentWorldTransform = &(skeleton->GetOwnerSkeletalModel()->WorldTransform());
105 parentLocalTransform = &(skeleton->GetOwnerSkeletalModel()->Transform());
106 }
107 }
108 else
109 {
110 parentLocalTransform = pose.GetTransform(parentBoneIndex);
111 parentWorldTransform = worldPose.GetTransform(parentBoneIndex);
112 }
113
114 worldMatrixUpdater.UpdateMaya(
115 matrix,
116 worldPose.GetTransform(index),
117 *pose.GetTransform(index),
118 *parentWorldTransform,
119 *parentLocalTransform,
120 ut::CheckFlag(bone.GetFlags(), ResBoneData::FLAG_IS_SEGMENTSCALE_COMPENSATE));
121 }
122
123 skeleton->PostCalculateMatrixSignal()(skeleton, index);
124 }
125 }
126 else if(scalingRule == WorldMatrixUpdater::SCALING_RULE_STANDARD)
127 {
128 for (Skeleton::MatrixPose::MatrixArray::iterator matrix = range.first; matrix != range.second; ++matrix, ++index)
129 {
130 skeleton->PreCalculateMatrixSignal()(skeleton, index);
131
132 // CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED を 0 にしたときでもコールバックは呼ばれます。
133 if ( pose.GetTransform(index)->IsEnabledFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED) )
134 {
135 ResBone bone = resSkeleton.GetBones(index);
136 int parentBoneIndex = bone.GetParentBoneIndex();
137 const CalculatedTransform* parentWorldTransform;
138 const CalculatedTransform* parentLocalTransform;
139
140 if (parentBoneIndex == -1)
141 {
142 if (isModelCoordinate)
143 {
144 parentWorldTransform = &CalculatedTransform::Identity();
145 parentLocalTransform = &CalculatedTransform::Identity();
146 }
147 else
148 {
149 parentWorldTransform = &(skeleton->GetOwnerSkeletalModel()->WorldTransform());
150 parentLocalTransform = &(skeleton->GetOwnerSkeletalModel()->Transform());
151 }
152 }
153 else
154 {
155 parentLocalTransform = pose.GetTransform(parentBoneIndex);
156 parentWorldTransform = worldPose.GetTransform(parentBoneIndex);
157 }
158
159 worldMatrixUpdater.UpdateBasic(
160 matrix,
161 worldPose.GetTransform(index),
162 *pose.GetTransform(index),
163 *parentWorldTransform,
164 *parentLocalTransform);
165 }
166
167 skeleton->PostCalculateMatrixSignal()(skeleton, index);
168 }
169 }
170 else // Softimage
171 {
172 for (Skeleton::MatrixPose::MatrixArray::iterator matrix = range.first; matrix != range.second; ++matrix, ++index)
173 {
174 skeleton->PreCalculateMatrixSignal()(skeleton, index);
175
176 // CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED を 0 にしたときでもコールバックは呼ばれます。
177 if ( pose.GetTransform(index)->IsEnabledFlags(CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED) )
178 {
179 ResBone bone = resSkeleton.GetBones(index);
180 int parentBoneIndex = bone.GetParentBoneIndex();
181 const CalculatedTransform* parentWorldTransform;
182 const CalculatedTransform* parentLocalTransform;
183
184 if (parentBoneIndex == -1)
185 {
186 if (isModelCoordinate)
187 {
188 parentWorldTransform = &CalculatedTransform::Identity();
189 parentLocalTransform = &CalculatedTransform::Identity();
190 }
191 else
192 {
193 parentWorldTransform = &(skeleton->GetOwnerSkeletalModel()->WorldTransform());
194 parentLocalTransform = &(skeleton->GetOwnerSkeletalModel()->Transform());
195 }
196 }
197 else
198 {
199 parentLocalTransform = pose.GetTransform(parentBoneIndex);
200 parentWorldTransform = worldPose.GetTransform(parentBoneIndex);
201 }
202
203 worldMatrixUpdater.UpdateXsi(
204 matrix,
205 worldPose.GetTransform(index),
206 *pose.GetTransform(index),
207 *parentWorldTransform,
208 *parentLocalTransform);
209 }
210
211 skeleton->PostCalculateMatrixSignal()(skeleton, index);
212 }
213 }
214 }
215
216 //----------------------------------------
217 void
UpdateView(Skeleton * skeleton,const BillboardUpdater & billboardUpdater,const Camera & camera) const218 SkeletonUpdater::UpdateView(
219 Skeleton* skeleton,
220 const BillboardUpdater& billboardUpdater,
221 const Camera& camera
222 ) const
223 {
224 NW_NULL_ASSERT(skeleton);
225
226 ResSkeleton resSkeleton = skeleton->GetResSkeleton();
227 NW_ASSERT(resSkeleton.IsValid());
228 Skeleton::TransformPose& pose = skeleton->LocalTransformPose();
229 Skeleton::TransformPose& worldPose = skeleton->WorldTransformPose();
230 SkeletalModel* model = skeleton->GetOwnerSkeletalModel();
231
232 math::VEC3 cameraPos = camera.WorldMatrix().GetColumn(3);
233
234 int index = 0;
235 Skeleton::MatrixPose::MatrixRange range = skeleton->WorldMatrixPose().GetAllMatrices();
236 for (Skeleton::MatrixPose::MatrixArray::iterator matrix = range.first; matrix != range.second; ++matrix, ++index)
237 {
238 if ( !pose.GetTransform(index)->IsEnabledFlagsOr(
239 CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED |
240 CalculatedTransform::FLAG_FORCE_VIEW_CALCULATION_ENABLED))
241 {
242 continue;
243 }
244
245 ResBone bone = resSkeleton.GetBones(index);
246 #if defined(NW_GFX_BILLBOARD_UPDATE_ENABLED)
247 ResBone::BillboardMode billboardMode = bone.GetBillboardMode();
248 if ( billboardMode != ResBone::BILLBOARD_MODE_OFF)
249 {
250 NW_ASSERTMSG(
251 !ut::CheckFlag(resSkeleton.GetFlags(), ResSkeletonData::FLAG_MODEL_COORDINATE),
252 "The bone for billboard needs to be world-coordinate.");
253
254 CalculatedTransform* worldTransform = worldPose.GetTransform(index);
255 CalculatedTransform* localTransform = pose.GetTransform(index);
256
257 billboardUpdater.Update(
258 &(*matrix),
259 camera.ViewMatrix(),
260 camera.InverseViewMatrix(),
261 cameraPos,
262 *worldTransform,
263 *localTransform,
264 billboardMode);
265
266 bool isScaleOne = worldTransform->IsEnabledFlags(CalculatedTransform::FLAG_IS_SCALE_ONE);
267
268 if (!isScaleOne)
269 {
270 math::MTX34 worldMatrix;
271 math::VEC3 rotateScale;
272 math::MTX34MultScale(&worldMatrix, &worldTransform->TransformMatrix(), &localTransform->Scale());
273 math::MTX34DecomposeToColumnScale(&rotateScale, &worldMatrix);
274
275 math::MTX33Mult(
276 &(*matrix),
277 *matrix,
278 math::MTX34().SetupScale(rotateScale));
279 }
280 }
281 #else
282 NW_UNUSED_VARIABLE(billboardUpdater);
283 #endif
284
285 // スキニング用にベースマトリクスと掛ける
286 bool isCalcSkiningMatrix =
287 ut::CheckFlag(bone.GetFlags(), ResBoneData::FLAG_HAS_SKINNING_MATRIX | ResBoneData::FLAG_IS_NEED_RENDERING);
288
289 if (isCalcSkiningMatrix)
290 {
291 math::MTX34Mult(
292 skeleton->SkiningMatrixPose().GetMatrix(index),
293 matrix,
294 &bone.GetInverseBaseMatrix());
295 }
296 }
297 }
298
299 } // namespace gfx
300 } // namespace nw
301