1 /*
2 Copyright (C) 2005-2007 Feeling Software Inc.
3 Portions of the code are:
4 Copyright (C) 2005-2007 Sony Computer Entertainment America
5
6 MIT License: http://www.opensource.org/licenses/mit-license.php
7 */
8 /*
9 Based on the FS Import classes:
10 Copyright (C) 2005-2006 Feeling Software Inc
11 Copyright (C) 2005-2006 Autodesk Media Entertainment
12 MIT License: http://www.opensource.org/licenses/mit-license.php
13 */
14
15 #include "StdAfx.h"
16 #include "FCDocument/FCDocument.h"
17 #include "FCDocument/FCDController.h"
18 #include "FCDocument/FCDGeometry.h"
19 #include "FCDocument/FCDGeometryMesh.h"
20 #include "FCDocument/FCDGeometryPolygons.h"
21 #include "FCDocument/FCDGeometrySource.h"
22 #include "FCDocument/FCDGeometrySpline.h"
23 #include "FCDocument/FCDSkinController.h"
24 #include "FCDocument/FCDEntityReference.h"
25
26 //
27 // FCDSkinController
28 //
29
30 ImplementObjectType(FCDSkinController);
31
FCDSkinController(FCDocument * document,FCDController * _parent)32 FCDSkinController::FCDSkinController(FCDocument* document, FCDController* _parent)
33 : FCDObject(document)
34 , parent(_parent)
35 , InitializeParameter(bindShapeTransform, FMMatrix44::Identity)
36 {
37 // Always create this.
38 target = new FCDEntityReference(document, parent);
39 }
40
~FCDSkinController()41 FCDSkinController::~FCDSkinController()
42 {
43 SAFE_RELEASE(target);
44 }
45
GetTargetUri() const46 FUUri FCDSkinController::GetTargetUri() const
47 {
48 return target->GetUri();
49 }
50
SetTargetUri(const FUUri & uri)51 void FCDSkinController::SetTargetUri(const FUUri& uri)
52 {
53 target->SetUri(uri);
54 }
55
GetTarget()56 FCDEntity* FCDSkinController::GetTarget()
57 {
58 return target->GetEntity();
59 }
60
GetTarget() const61 const FCDEntity* FCDSkinController::GetTarget() const
62 {
63 return target->GetEntity();
64 }
65
SetTarget(FCDEntity * _target)66 void FCDSkinController::SetTarget(FCDEntity* _target)
67 {
68 target->SetEntity(NULL);
69 SetNewChildFlag();
70
71 // Retrieve the actual base entity, as you can chain controllers.
72 FCDEntity* baseEntity = _target;
73 if (baseEntity != NULL && baseEntity->GetType() == FCDEntity::CONTROLLER)
74 {
75 baseEntity = ((FCDController*) baseEntity)->GetBaseGeometry();
76 }
77
78 if (baseEntity == NULL || baseEntity->GetType() != FCDEntity::GEOMETRY)
79 {
80 // The new target is no good!
81 return;
82 }
83
84 target->SetEntity(_target);
85 FCDGeometry* geometry = (FCDGeometry*) baseEntity;
86
87 // Retrieve the new vertex count
88 size_t vertexCount = 0;
89 if (geometry->IsMesh())
90 {
91 FCDGeometryMesh* mesh = geometry->GetMesh();
92 FCDGeometrySource* positionSource = mesh->GetPositionSource();
93 if (positionSource != NULL)
94 {
95 vertexCount = positionSource->GetValueCount();
96 }
97 }
98 else if (geometry->IsSpline())
99 {
100 FCDGeometrySpline* spline = geometry->GetSpline();
101 vertexCount = spline->GetTotalCVCount();
102 }
103
104 // Modify the list of influences to match the new target's vertex count.
105 if (influences.size() != 0)
106 {
107 // This is only really acceptable with equivalent meshes. Ensure we
108 // are still compatable.
109 FUAssert(vertexCount == influences.size(), SetInfluenceCount(vertexCount));
110 }
111 else
112 {
113 SetInfluenceCount(vertexCount);
114 }
115 }
116
SetInfluenceCount(size_t count)117 void FCDSkinController::SetInfluenceCount(size_t count)
118 {
119 // None of the list structures are allocated directly: resize() will work fine.
120 influences.resize(count);
121 SetDirtyFlag();
122 }
123
SetJointCount(size_t count)124 void FCDSkinController::SetJointCount(size_t count)
125 {
126 joints.resize(count);
127 SetDirtyFlag();
128 }
129
AddJoint(const fm::string jSubId,const FMMatrix44 & bindPose)130 FCDSkinControllerJoint* FCDSkinController::AddJoint(const fm::string jSubId, const FMMatrix44& bindPose)
131 {
132 SetJointCount(GetJointCount() + 1);
133 FCDSkinControllerJoint* joint = &joints.back();
134 joint->SetId(jSubId);
135 joint->SetBindPoseInverse(bindPose);
136 SetDirtyFlag();
137 return joint;
138 }
139
140
141 // Reduce the number of joints influencing each vertex to a maximum count
ReduceInfluences(uint32 maxInfluenceCount,float minimumWeight)142 void FCDSkinController::ReduceInfluences(uint32 maxInfluenceCount, float minimumWeight)
143 {
144 // Pre-cache an empty weight list to the reduced count
145 fm::vector<FCDJointWeightPair> reducedWeights;
146 reducedWeights.reserve(maxInfluenceCount + 1);
147
148 for (FCDSkinControllerVertex* itM = influences.begin(); itM != influences.end(); ++itM)
149 {
150 FCDSkinControllerVertex& influence = (*itM);
151 size_t oldInfluenceCount = influence.GetPairCount();
152
153 // Reduce the weights, keeping only the more important ones using a sorting algorithm.
154 // Also, calculate the current total of the weights, to re-normalize the reduced weights
155 float oldTotal = 0.0f;
156 reducedWeights.clear();
157 for (size_t i = 0; i < oldInfluenceCount; ++i)
158 {
159 FCDJointWeightPair* pair = influence.GetPair(i);
160 if (pair->weight >= minimumWeight)
161 {
162 FCDJointWeightPair* itRW = reducedWeights.begin();
163 for (; itRW != reducedWeights.end() && (*itRW).weight > pair->weight; ++itRW) {}
164 if (itRW != reducedWeights.end() || reducedWeights.size() <= maxInfluenceCount)
165 {
166 reducedWeights.insert(itRW, *pair);
167 if (reducedWeights.size() > maxInfluenceCount) reducedWeights.pop_back();
168 }
169 }
170 oldTotal += pair->weight;
171 }
172
173 size_t newInfluenceCount = reducedWeights.size();
174 if (oldInfluenceCount > newInfluenceCount)
175 {
176 // Replace the old weights and re-normalize to their old total
177 influence.SetPairCount(newInfluenceCount);
178 for (size_t i = 0; i < newInfluenceCount; ++i) (*(influence.GetPair(i))) = reducedWeights[i];
179
180 float newTotal = 0.0f;
181 for (size_t i = 0; i < newInfluenceCount; ++i) newTotal += influence.GetPair(i)->weight;
182 float renormalizingFactor = oldTotal / newTotal;
183 for (size_t i = 0; i < newInfluenceCount; ++i) influence.GetPair(i)->weight *= renormalizingFactor;
184 }
185 }
186
187 SetDirtyFlag();
188 }
189
190 //
191 // FCDSkinControllerVertex
192 //
193
194
SetPairCount(size_t count)195 void FCDSkinControllerVertex::SetPairCount(size_t count)
196 {
197 pairs.resize(count);
198 }
199
AddPair(int32 jointIndex,float weight)200 void FCDSkinControllerVertex::AddPair(int32 jointIndex, float weight)
201 {
202 pairs.push_back(FCDJointWeightPair(jointIndex, weight));
203 }
204
205 //
206 // FCDSkinControllerJoint
207 //
208
SetId(const fm::string & _id)209 void FCDSkinControllerJoint::SetId(const fm::string& _id)
210 {
211 // Do not inline, since the line below does memory allocation.
212 id = _id;
213 }
214