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: 25728 $
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 Result
CreateSkeletalAnimGroup(os::IAllocator * allocator)112 SkeletalModel::CreateSkeletalAnimGroup(os::IAllocator* allocator)
113 {
114     Result result = INITIALIZE_RESULT_OK;
115 
116     AnimBinding* animBinding = GetAnimBinding();
117     if (animBinding == NULL)
118     {
119         return result;
120     }
121 
122     ResSceneObject resSceneObject = GetResSceneObject();
123     ResSkeletalModel resModel = *reinterpret_cast<ResSkeletalModel*>(&resSceneObject);
124     NW_ASSERT(resModel.IsValid());
125 
126     ResSkeleton resSkeleton = resModel.GetSkeleton();
127     Skeleton::TransformPose& pose = m_Skeleton->LocalTransformPose();
128     Skeleton::OriginalPose& originalPose = m_Skeleton->LocalOriginalPose();
129 
130     const int animGroupCount = resModel.GetAnimGroupsCount();
131     for (int animGroupIdx = 0; animGroupIdx < animGroupCount; ++animGroupIdx)
132     {
133         anim::ResAnimGroup resAnimGroup = resModel.GetAnimGroups(animGroupIdx);
134         const int targetType = resAnimGroup.GetTargetType();
135         const bool transformFlag =
136             (resAnimGroup.GetFlags() & anim::ResAnimGroup::FLAG_IS_CALCULATED_TRANSFORM) != 0;
137         if (transformFlag &&
138             targetType == anim::ResGraphicsAnimGroup::TARGET_TYPE_BONE)
139         {
140             AnimGroup* animGroup = AnimGroup::Builder()
141                 .ResAnimGroup(resAnimGroup)
142                 .SetSceneNode(this)
143                 .UseOriginalValue(true)
144                 .Create(allocator);
145 
146             if (animGroup == NULL)
147             {
148                 result |= Result::MASK_FAIL_BIT;
149             }
150 
151             NW_ENSURE_AND_RETURN(result);
152 
153             const int animMemberCount = animGroup->GetMemberCount();
154             for (int memberIdx = 0; memberIdx < animMemberCount; ++memberIdx)
155             {
156                 anim::ResAnimGroupMember resAnimGroupMember =
157                     animGroup->GetResAnimGroupMember(memberIdx);
158 
159                 // TODO: ResBoneMemberDataの情報を利用する
160                 ResBone bone = resSkeleton.GetBones(resAnimGroupMember.GetPath());
161                 NW_ASSERT(bone.IsValid());
162                 const int boneIdx = bone.GetIndex();
163                 animGroup->SetTargetObjectIndex(memberIdx, boneIdx);
164                 animGroup->SetTargetPtr(memberIdx, pose.GetTransform(boneIdx));
165                 animGroup->SetOriginalValue(memberIdx, originalPose.GetTransform(boneIdx));
166 
167                 void* object = GetAnimTargetObject(resAnimGroupMember);
168                 animGroup->SetTargetObject(memberIdx, object);
169             }
170             animBinding->SetAnimGroup(animGroupIdx, animGroup);
171             m_SkeletalAnimGroup = animGroup;
172             m_SkeletalAnimBindingIndex = animGroupIdx;
173             break; // 他にスケルタルモデル専用のアニメーショングループがないので
174         }
175     }
176 
177     return result;
178 }
179 
180 //----------------------------------------
181 void*
GetAnimTargetObject(const anim::ResAnimGroupMember & anim)182 SkeletalModel::GetAnimTargetObject(const anim::ResAnimGroupMember& anim)
183 {
184     switch(anim.GetObjectType())
185     {
186     case nw::anim::ResAnimGroupMember::OBJECT_TYPE_BONE:
187         {
188             nw::anim::ResBoneMember member = ResStaticCast<nw::anim::ResBoneMember>(anim);
189             const char* boneName = member.GetBoneName();
190 
191             const int boneIndex =
192                 GetResSkeletalModel().GetSkeleton().GetBones(boneName).GetIndex();
193 
194             // 型が変更されたらコンパイルエラーが起きるよう、
195             // いったん目的の型に代入してからreturnで返す
196             CalculatedTransform* ptr =
197                 GetSkeleton()->LocalTransformPose().GetTransform(boneIndex);
198             return ptr;
199         }
200 
201     default:
202         NW_ASSERT(false);
203         return NULL;
204     }
205 }
206 
207 //----------------------------------------
208 Result
Initialize(os::IAllocator * allocator)209 SkeletalModel::Initialize(os::IAllocator* allocator)
210 {
211     Result result = INITIALIZE_RESULT_OK;
212 
213     result |= Model::Initialize(allocator);
214     NW_ENSURE_AND_RETURN(result);
215 
216     result |= CreateSkeletalAnimGroup(allocator);
217     NW_ENSURE_AND_RETURN(result);
218 
219     return result;
220 }
221 
222 } // namespace gfx
223 } // namespace nw
224