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