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