1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_SkeletalModel.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: 28001 $
14 *---------------------------------------------------------------------------*/
15
16 #include "precompiled.h"
17
18 #include <nw/gfx/gfx_SkeletalModel.h>
19 #include <nw/gfx/gfx_ISceneVisitor.h>
20 #include <nw/gfx/gfx_AnimObject.h>
21
22 #include <nw/anim/res/anim_ResAnimGroup.h>
23
24 #include <nw/ut/ut_ResUtil.h>
25 #include <nw/ut/ut_ResDictionary.h>
26 #include <nw/ut/ut_Foreach.h>
27
28 namespace nw
29 {
30 namespace gfx
31 {
32
33 NW_UT_RUNTIME_TYPEINFO_DEFINITION( SkeletalModel, Model );
34
35 //----------------------------------------
36 SkeletalModel*
Create(SceneNode * parent,ResSceneObject resource,os::IAllocator * allocator)37 SkeletalModel::Builder::Create(
38 SceneNode* parent,
39 ResSceneObject resource,
40 os::IAllocator* allocator)
41 {
42 NW_NULL_ASSERT(allocator);
43
44 ResSkeletalModel resModel = ResStaticCast<ResSkeletalModel>(resource);
45
46 GfxPtr<Skeleton> skeleton;
47 bool isSharedSkeleton = true;
48 if (m_Description.sharedSkeleton != NULL)
49 {
50 // 所有権の移動を行いません。
51 skeleton.Reset(m_Description.sharedSkeleton, false);
52 isSharedSkeleton = true;
53 }
54 else
55 {
56 // スケルトン作成
57 ResSkeleton resSkeleton = resModel.GetSkeleton();
58 NW_ASSERT(resSkeleton.IsValid());
59 Skeleton::TransformPose::TransformArray poseTransforms(resSkeleton.GetBonesCount(), allocator);
60 ResBoneArray bones = resSkeleton.GetBones();
61 ResBoneArray::iterator bonesEnd = bones.end();
62 for (ResBoneArray::iterator bone = bones.begin(); bone != bonesEnd; ++bone)
63 {
64 // リソースから計算済みトランスフォームへデータをコピーします。
65 poseTransforms.PushBackFast(*bone);
66 }
67 skeleton.Reset(StandardSkeleton::Create(
68 resSkeleton,
69 m_Description.maxCallbacks,
70 m_Description.isFixedSizeMemory,
71 poseTransforms,
72 allocator));
73
74 isSharedSkeleton = false;
75 }
76
77 // モデル作成
78 void* memory = allocator->Alloc(sizeof(SkeletalModel));
79 NW_NULL_ASSERT(memory);
80
81 SkeletalModel* model = new(memory) SkeletalModel(
82 allocator,
83 resModel,
84 skeleton,
85 isSharedSkeleton,
86 m_Description);
87
88 Result result = model->Initialize(allocator);
89 NW_ASSERT(result.IsSuccess());
90
91 if (parent)
92 {
93 bool isAttached = parent->AttachChild(model);
94 NW_ASSERT(isAttached);
95 }
96
97 return model;
98 }
99
100 //----------------------------------------
101 void
Accept(ISceneVisitor * visitor)102 SkeletalModel::Accept(
103 ISceneVisitor* visitor
104 )
105 {
106 visitor->VisitSkeletalModel(this);
107 AcceptChildren(visitor);
108 }
109
110 //----------------------------------------
111 void
SetFullBakedAnimEnabled(bool enable)112 SkeletalModel::SetFullBakedAnimEnabled(bool enable)
113 {
114 m_FullBakedAnimEnabled = enable;
115
116 // フルベイクアニメを使用する場合は、モデル座標系で描画する
117 if (enable)
118 {
119 m_Skeleton->GetResSkeleton().EnableFlags(ResSkeletonData::FLAG_MODEL_COORDINATE);
120 }
121 else
122 {
123 m_Skeleton->GetResSkeleton().DisableFlags(ResSkeletonData::FLAG_MODEL_COORDINATE);
124 }
125
126 NW_NULL_ASSERT(m_SkeletalAnimGroup);
127 SetupAnimGroup(m_SkeletalAnimGroup, enable);
128 }
129
130 //----------------------------------------
131 Result
CreateSkeletalAnimGroup(os::IAllocator * allocator)132 SkeletalModel::CreateSkeletalAnimGroup(os::IAllocator* allocator)
133 {
134 Result result = INITIALIZE_RESULT_OK;
135
136 AnimBinding* animBinding = GetAnimBinding();
137 if (animBinding == NULL)
138 {
139 return result;
140 }
141
142 ResSceneObject resSceneObject = GetResSceneObject();
143 ResSkeletalModel resModel = *reinterpret_cast<ResSkeletalModel*>(&resSceneObject);
144 NW_ASSERT(resModel.IsValid());
145
146 ResSkeleton resSkeleton = resModel.GetSkeleton();
147 Skeleton::TransformPose& pose = m_Skeleton->LocalTransformPose();
148 Skeleton::OriginalPose& originalPose = m_Skeleton->LocalOriginalPose();
149
150 const int animGroupCount = resModel.GetAnimGroupsCount();
151 for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx)
152 {
153 anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx);
154 const int targetType = resAnimGroup.GetTargetType();
155 const bool transformFlag =
156 (resAnimGroup.GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) != 0;
157 if (transformFlag &&
158 targetType == anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE)
159 {
160 AnimGroup* animGroup = AnimGroup::Builder()
161 .ResAnimGroup(resAnimGroup)
162 .SetSceneNode(this)
163 .UseOriginalValue(true)
164 .Create(allocator);
165
166 if (animGroup == NULL)
167 {
168 result |= Result::MASK_FAIL_BIT;
169 }
170
171 NW_ENSURE_AND_RETURN(result);
172
173 const int animMemberCount = animGroup->GetMemberCount();
174 for (int memberIdx = 0; memberIdx < animMemberCount; ++memberIdx)
175 {
176 anim::ResAnimGroupMember resAnimGroupMember =
177 animGroup->GetResAnimGroupMember(memberIdx);
178
179 // TODO: ResBoneMemberDataの情報を利用する
180 ResBone bone = resSkeleton.GetBones(resAnimGroupMember.GetPath());
181 NW_ASSERT(bone.IsValid());
182 const int boneIdx = bone.GetIndex();
183 animGroup->SetTargetObjectIndex(memberIdx, boneIdx);
184 animGroup->SetOriginalValue(memberIdx, originalPose.GetTransform(boneIdx));
185
186 void* object = GetAnimTargetObject(resAnimGroupMember);
187 animGroup->SetTargetObject(memberIdx, object);
188
189 // TargetPtrは、SetupAnimGroup()で設定する
190 }
191 animBinding->SetAnimGroup(animGroupIdx, animGroup);
192 m_SkeletalAnimGroup = animGroup;
193 m_SkeletalAnimBindingIndex = animGroupIdx;
194
195 SetupAnimGroup(animGroup, m_FullBakedAnimEnabled);
196
197 break; // 他にスケルタルモデル専用のアニメーショングループがないので
198 }
199 }
200
201 return result;
202 }
203
204 //----------------------------------------
205 void*
GetAnimTargetObject(const anim::ResAnimGroupMember & anim)206 SkeletalModel::GetAnimTargetObject(const anim::ResAnimGroupMember& anim)
207 {
208 switch(anim.GetObjectType())
209 {
210 case nw::anim::ResAnimGroupMember::OBJECT_TYPE_BONE:
211 {
212 nw::anim::ResBoneMember member = ResStaticCast<nw::anim::ResBoneMember>(anim);
213 const char* boneName = member.GetBoneName();
214
215 const int boneIndex =
216 GetResSkeletalModel().GetSkeleton().GetBones(boneName).GetIndex();
217
218 // 型が変更されたらコンパイルエラーが起きるよう、
219 // いったん目的の型に代入してからreturnで返す
220 CalculatedTransform* ptr =
221 GetSkeleton()->LocalTransformPose().GetTransform(boneIndex);
222 return ptr;
223 }
224
225 default:
226 NW_ASSERT(false);
227 return NULL;
228 }
229 }
230
231 //----------------------------------------
232 Result
Initialize(os::IAllocator * allocator)233 SkeletalModel::Initialize(os::IAllocator* allocator)
234 {
235 Result result = INITIALIZE_RESULT_OK;
236
237 result |= Model::Initialize(allocator);
238 NW_ENSURE_AND_RETURN(result);
239
240 if (!m_SharingSkeleton)
241 {
242 result |= CreateSkeletalAnimGroup(allocator);
243 NW_ENSURE_AND_RETURN(result);
244 }
245
246 return result;
247 }
248
249 //----------------------------------------
250 void
SetupAnimGroup(AnimGroup * animGroup,bool fullBakedAnimEnabled) const251 SkeletalModel::SetupAnimGroup(AnimGroup* animGroup, bool fullBakedAnimEnabled) const
252 {
253 const int animMemberCount = animGroup->GetMemberCount();
254 for (int memberIdx = 0; memberIdx < animMemberCount; ++memberIdx)
255 {
256 anim::ResAnimGroupMember resAnimGroupMember =
257 animGroup->GetResAnimGroupMember(memberIdx);
258
259 // TODO: ResBoneMemberDataの情報を利用する
260 ResBone bone = m_Skeleton->GetResSkeleton().GetBones(resAnimGroupMember.GetPath());
261 NW_ASSERT(bone.IsValid());
262 const int boneIdx = bone.GetIndex();
263
264 if (fullBakedAnimEnabled)
265 {
266 // フルベイクアニメの場合は、ワールドマトリクスを直接更新する
267 void* target = m_Skeleton->WorldMatrixPose().GetMatrix(boneIdx);
268 animGroup->SetTargetPtr(memberIdx, target);
269 }
270 else
271 {
272 // 通常はボーンのローカルトランスフォームを更新する
273 void* target = m_Skeleton->LocalTransformPose().GetTransform(boneIdx);
274 animGroup->SetTargetPtr(memberIdx, target);
275 }
276 }
277
278 m_SkeletalAnimGroup->SetFullBakedAnimEnabled(fullBakedAnimEnabled);
279 }
280
281 } // namespace gfx
282 } // namespace nw
283