1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/3d/u_skeleton.h"
24 #include "nel/3d/u_bone.h"
25 #include "nel/3d/u_driver.h"
26 #include "nel/misc/algo.h"
27 #include "nel/misc/progress_callback.h"
29 #include "game_share/gender.h"
33 using namespace NLMISC
;
36 //using CSkeletonGabarit::EBoneCategory;
39 H_AUTO_DECL(RZ_CSkeletonGabarit
)
41 extern UDriver
*Driver
;
43 CGabaritSet GabaritSet
;
48 CSkeletonGabarit::EBoneCategory Category
;
52 { "Bip01 Head_Second", CSkeletonGabarit::Other },
53 { "Bip01 Ponytail1_Second", CSkeletonGabarit::Other },
54 { "Bip01 L Finger0_Second", CSkeletonGabarit::Arm },
55 { "Bip01 L Finger1_Second", CSkeletonGabarit::Arm },
56 { "Bip01 L Finger2_Second", CSkeletonGabarit::Arm },
57 { "Bip01 L Finger3_Second", CSkeletonGabarit::Arm },
58 { "Bip01 L Finger4_Second", CSkeletonGabarit::Arm },
59 { "Bip01 L Toe0_Second", CSkeletonGabarit::Legs },
60 { "Bip01 R Toe0_Second", CSkeletonGabarit::Legs }
62 { "Bip01 Pelvis", CSkeletonGabarit::Torso
},
63 { "Bip01 Spine", CSkeletonGabarit::Torso
},
64 { "Bip01 Spine1", CSkeletonGabarit::Torso
},
65 { "Bip01 Spine2", CSkeletonGabarit::Torso
},
66 { "Bip01 Neck", CSkeletonGabarit::Other
},
67 { "Bip01 Head", CSkeletonGabarit::Other
},
68 { "Bip01 Ponytail1", CSkeletonGabarit::Other
},
69 { "Bip01 Ponytail11", CSkeletonGabarit::Other
},
70 { "Bip01 L Clavicle", CSkeletonGabarit::Torso
},
71 { "Bip01 L UpperArm", CSkeletonGabarit::Arm
},
72 { "Bip01 L Forearm", CSkeletonGabarit::Arm
},
73 { "Bip01 L Hand", CSkeletonGabarit::Arm
},
74 { "Bip01 L Finger0", CSkeletonGabarit::Arm
},
75 { "Bip01 L Finger01", CSkeletonGabarit::Arm
},
76 { "Bip01 L Finger02", CSkeletonGabarit::Arm
},
77 { "Bip01 L Finger1", CSkeletonGabarit::Arm
},
78 { "Bip01 L Finger11", CSkeletonGabarit::Arm
},
79 { "Bip01 L Finger12", CSkeletonGabarit::Arm
},
80 { "Bip01 L Finger2", CSkeletonGabarit::Arm
},
81 { "Bip01 L Finger21", CSkeletonGabarit::Arm
},
82 { "Bip01 L Finger22", CSkeletonGabarit::Arm
},
83 { "Bip01 L Finger3", CSkeletonGabarit::Arm
},
84 { "Bip01 L Finger31", CSkeletonGabarit::Arm
},
85 { "Bip01 L Finger32", CSkeletonGabarit::Arm
},
86 { "Bip01 L Finger4", CSkeletonGabarit::Arm
},
87 { "Bip01 L Finger41", CSkeletonGabarit::Arm
},
88 { "Bip01 L Finger42", CSkeletonGabarit::Arm
},
89 { "Bip01 R Clavicle", CSkeletonGabarit::Torso
},
90 { "Bip01 R UpperArm", CSkeletonGabarit::Arm
},
91 { "Bip01 R Forearm", CSkeletonGabarit::Arm
},
92 { "Bip01 R Hand", CSkeletonGabarit::Arm
},
93 { "Bip01 R Finger0", CSkeletonGabarit::Arm
},
94 { "Bip01 R Finger01", CSkeletonGabarit::Arm
},
95 { "Bip01 R Finger02", CSkeletonGabarit::Arm
},
96 // TRAP : not present in the skeleton : no more used ? { "Bip01 R Finger0R", CSkeletonGabarit::Arm },
97 { "Bip01 R Finger1", CSkeletonGabarit::Arm
},
98 { "Bip01 R Finger11", CSkeletonGabarit::Arm
},
99 { "Bip01 R Finger12", CSkeletonGabarit::Arm
},
100 // TRAP : not present in the skeleton : no more used ? { "Bip01 R Finger1R", CSkeletonGabarit::Arm },
101 { "Bip01 R Finger2", CSkeletonGabarit::Arm
},
102 { "Bip01 R Finger21", CSkeletonGabarit::Arm
},
103 { "Bip01 R Finger22", CSkeletonGabarit::Arm
},
104 // TRAP : not present in the skeleton : no more used ? { "Bip01 R Finger2R", CSkeletonGabarit::Arm },
105 { "Bip01 R Finger3", CSkeletonGabarit::Arm
},
106 { "Bip01 R Finger31", CSkeletonGabarit::Arm
},
107 { "Bip01 R Finger32", CSkeletonGabarit::Arm
},
108 // TRAP : not present in the skeleton : no more used ? { "Bip01 R Finger3R", CSkeletonGabarit::Arm },
109 { "Bip01 R Finger4", CSkeletonGabarit::Arm
},
110 { "Bip01 R Finger41", CSkeletonGabarit::Arm
},
111 { "Bip01 R Finger42", CSkeletonGabarit::Arm
},
112 // TRAP : not present in the skeleton : no more used ? { "Bip01 R Finger4R", CSkeletonGabarit::Arm },
113 { "Bip01 L Thigh", CSkeletonGabarit::Legs
},
114 { "Bip01 L Calf", CSkeletonGabarit::Legs
},
115 { "Bip01 L Foot", CSkeletonGabarit::Legs
},
116 { "Bip01 L Toe0", CSkeletonGabarit::Legs
},
117 { "Bip01 R Thigh", CSkeletonGabarit::Legs
},
118 { "Bip01 R Calf", CSkeletonGabarit::Legs
},
119 { "Bip01 R Foot", CSkeletonGabarit::Legs
},
120 { "Bip01 R Toe0", CSkeletonGabarit::Legs
},
121 { "sein_droit", CSkeletonGabarit::Breast
},
122 { "sein_gauche", CSkeletonGabarit::Breast
}
125 //===================================================================================
126 CSkeletonGabarit::CSkeletonGabarit()
128 H_AUTO_USE(RZ_CSkeletonGabarit
)
129 nlctassert(sizeof(boneInfos
) / sizeof(boneInfos
[0]) == NumBones
);
130 std::fill(BoneScale
, BoneScale
+ NumBones
, CVector(1, 1, 1));
131 std::fill(BoneSkinScale
, BoneSkinScale
+ NumBones
, CVector(1, 1, 1));
135 //===================================================================================
136 void CSkeletonGabarit::buildFromSkeleton(NL3D::USkeleton src
, const std::string
&skelName
, bool bMale
)
138 H_AUTO_USE(RZ_CSkeletonGabarit
)
139 nlassert(!src
.empty());
140 // get the bones we need
141 for(uint k
= 0; k
< NumBones
; ++k
)
143 sint boneID
= src
.getBoneIdByName(boneIndexToName(k
));
146 // If the skeleton is male and we try to get breast its normal that we dont found it
147 if ( ! ((boneIndexToCategory(k
) == CSkeletonGabarit::Breast
) && (bMale
)) )
148 nlwarning("CSkeletonGabarit : can't get bone %s for skeleton %s", boneIndexToName(k
), skelName
.c_str());
149 BoneScale
[k
].set(1, 1, 1);
150 BoneSkinScale
[k
].set(1, 1, 1);
154 UBone bone
= src
.getBone((uint
) boneID
);
155 bone
.setTransformMode(UTransformable::RotQuat
);
156 BoneScale
[k
] = bone
.getScale();
157 BoneSkinScale
[k
] = bone
.getSkinScale();
161 /*NLMISC::CAABBox bbox;
162 src.computeCurrentBBox(bbox, NULL, 0.f, true);
163 HeightScale = 2.f * bbox.getHalfSize().z;
169 sint boneId
= src
.getBoneIdByName("Bip01 R Thigh");
172 UBone bone
= src
.getBone(boneId
);
173 HeightScale
= bone
.getScale().x
;
178 //===================================================================================
179 const char *CSkeletonGabarit::boneIndexToName(uint id
)
181 H_AUTO_USE(RZ_CSkeletonGabarit
)
182 nlassert(id
< NumBones
);
183 return boneInfos
[id
].Name
;
186 //===================================================================================
187 CSkeletonGabarit::EBoneCategory
CSkeletonGabarit::boneIndexToCategory(uint id
)
189 H_AUTO_USE(RZ_CSkeletonGabarit
)
190 nlassert(id
< NumBones
);
191 return boneInfos
[id
].Category
;
194 //===================================================================================
195 //===================================================================================
197 void CGabaritSet::loadGabarits (NLMISC::IProgressCallback
&progress
)
199 H_AUTO_USE(RZ_CSkeletonGabarit
)
200 static const char *genderPrefix
[] = { "HOM_skel", "HOF_skel" };
201 static const char *racePrefix
[] = { "TR_", "FY_", "MA_", "ZO_" };
202 static const char *heightPrefix
[] = { "_Small", "_Mid", "_Big" };
203 static const char *widthPrefix
[] = { "_Slim", "", "_Fat" };
205 // create a dummy scene to load the skeletons
206 UScene
*scene
= Driver
->createScene(false);
209 nlwarning("CGabaritSet::loadGabarits : can't create scene to load skeletons");
212 for(uint g
= 0; g
< NumGender
; ++g
)
215 progress
.progress ((float)g
/(float)NumGender
);
216 progress
.pushCropedValues ((float)g
/(float)NumGender
, (float)(g
+1)/(float)NumGender
);
218 for(uint r
= 0; r
< NumRace
; ++r
)
221 progress
.progress ((float)r
/(float)NumRace
);
222 progress
.pushCropedValues ((float)r
/(float)NumRace
, (float)(r
+1)/(float)NumRace
);
224 for(uint h
= 0; h
< NumHeights
; ++h
)
227 progress
.progress ((float)h
/(float)NumHeights
);
228 progress
.pushCropedValues ((float)h
/(float)NumHeights
, (float)(h
+1)/(float)NumHeights
);
230 for(uint w
= 0; w
< NumWidths
; ++w
)
233 progress
.progress ((float)w
/(float)NumWidths
);
235 string skelName
= string(racePrefix
[r
]) + genderPrefix
[g
];
236 if (h
!= 1 || w
!= 1)
238 skelName
+= string(heightPrefix
[h
]) + widthPrefix
[w
];
241 USkeleton skel
= scene
->createSkeleton(skelName
);
244 nlwarning("CGabaritSet::loadGabarits : can't load skeleton %s", skelName
.c_str());
248 _Gabarit
[g
][r
][h
][w
].buildFromSkeleton(skel
, skelName
, g
== GSGENDER::male
);
249 scene
->deleteSkeleton(skel
);
254 progress
.popCropedValues ();
258 progress
.popCropedValues ();
262 progress
.popCropedValues ();
264 Driver
->deleteScene(scene
);
267 //===================================================================================
268 sint
CGabaritSet::peopleToIndex(EGSPD::CPeople::TPeople people
)
270 H_AUTO_USE(RZ_CSkeletonGabarit
)
274 case EGSPD::CPeople::Fyros
: race
= 1; break;
275 case EGSPD::CPeople::Tryker
: race
= 0; break;
276 case EGSPD::CPeople::Matis
: race
= 2; break;
277 case EGSPD::CPeople::Zorai
: race
= 3; break;
279 nlwarning("CGabaritSet::peopleToIndex : not a supported race");
285 //===================================================================================
286 void CGabaritSet::applyGabarit(NL3D::USkeleton dest
, uint gender
, EGSPD::CPeople::TPeople people
, float height
, float torsoWidth
, float armsWidth
, float legsWidth
, float breastSize
, float *finalHeightScale
)
288 H_AUTO_USE(RZ_CSkeletonGabarit
)
291 nlwarning("<CGabaritSet::applyGabarit> Skeleton NULL (gender=%d People=%d)",gender
,people
);
294 if (gender
>= NumGender
) return;
296 sint race
= peopleToIndex(people
);
297 if (race
== -1) return;
299 clamp(height
, -1, 1);
300 clamp(torsoWidth
, -1, 1);
301 clamp(armsWidth
, -1, 1);
302 clamp(legsWidth
, -1, 1);
303 clamp(breastSize
, -1, 1);
306 // we blend between the 4 nearest gabarits
307 // Slim -1 Normal 0 Fat 1
308 // +--------+--------+ Big 1
313 // +--------+--------+ Mid 0
318 // +--------+--------+ Small - 1
321 // a set of 4 gabarit between which to blend
331 CSkeletonGabarit
*TL
;
332 CSkeletonGabarit
*TR
;
333 CSkeletonGabarit
*BL
;
334 CSkeletonGabarit
*BR
;
337 // Choose the right gabarits
338 float *widthsTab
[CSkeletonGabarit::NumBoneCategory
] = { &armsWidth
, &torsoWidth
, &legsWidth
, &breastSize
};
339 CGabaritBlend gbTab
[CSkeletonGabarit::NumBoneCategory
];
340 float blendTab
[CSkeletonGabarit::NumBoneCategory
];
342 // build each set of 4 gabarits
344 for(k
= 0; k
< CSkeletonGabarit::NumBoneCategory
; ++k
)
346 float width
= *widthsTab
[k
];
347 gbTab
[k
].BL
= &_Gabarit
[gender
][race
][height
>= 0 ? 1 : 0][width
>= 0 ? 1 : 0];
348 gbTab
[k
].BR
= &_Gabarit
[gender
][race
][height
>= 0 ? 1 : 0][width
>= 0 ? 2 : 1];
349 gbTab
[k
].TL
= &_Gabarit
[gender
][race
][height
>= 0 ? 2 : 1][width
>= 0 ? 1 : 0];
350 gbTab
[k
].TR
= &_Gabarit
[gender
][race
][height
>= 0 ? 2 : 1][width
>= 0 ? 2 : 1];
352 blendTab
[k
] = width
>= 0 ? width
: 1.f
+ width
;
355 float heightBlend
= height
>= 0 ? height
: 1.f
+ height
;
359 for(k
= 0; k
< CSkeletonGabarit::NumBones
; ++k
)
361 // get the bone in the dest skeleton
362 sint boneID
= dest
.getBoneIdByName(CSkeletonGabarit::boneIndexToName(k
));
365 UBone bone
= dest
.getBone(boneID
);
366 CSkeletonGabarit::EBoneCategory boneCategory
= CSkeletonGabarit::boneIndexToCategory(k
);
367 if (boneCategory
!= CSkeletonGabarit::Other
)
369 const CGabaritBlend
&gb
= gbTab
[boneCategory
]; // takes the gabarit blend matching the bone category
370 bone
.setTransformMode(UTransform::RotQuat
);
373 CVector scale
= NLMISC::computeBilinear(gb
.BL
->BoneScale
[k
],
377 blendTab
[boneCategory
],
379 bone
.setScale(scale
);
382 CVector skinScale
= NLMISC::computeBilinear( gb
.BL
->BoneSkinScale
[k
],
383 gb
.BR
->BoneSkinScale
[k
],
384 gb
.TR
->BoneSkinScale
[k
],
385 gb
.TL
->BoneSkinScale
[k
],
386 blendTab
[boneCategory
],
388 bone
.setSkinScale(skinScale
);
393 if (finalHeightScale
)
395 *finalHeightScale
= NLMISC::computeBilinear(gbTab
[0].BL
->HeightScale
,
396 gbTab
[0].BR
->HeightScale
,
397 gbTab
[0].TR
->HeightScale
,
398 gbTab
[0].TL
->HeightScale
,
406 //===================================================================================
407 float CGabaritSet::getRefHeightScale(uint gender
, EGSPD::CPeople::TPeople people
)
409 H_AUTO_USE(RZ_CSkeletonGabarit
)
410 nlassert(gender
< 2);
411 sint peopleIndex
= peopleToIndex(people
);
412 if (peopleIndex
== -1) return 0.f
;
413 return _Gabarit
[gender
][peopleIndex
][1][1].HeightScale
; // return mean size