1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 // ------------------------------------------------------------------------------------------------
25 #include "character_3d.h"
26 #include "interface_manager.h"
28 #include "../color_slot_manager.h"
29 #include "../sheet_manager.h"
30 #include "../gabarit.h"
32 #include "../time_client.h"
33 #include "../player_cl.h"
34 #include "../player_r2_cl.h"
35 #include "../entities.h"
37 #include "../r2/editor.h"
38 #include "../client_cfg.h"
40 // ------------------------------------------------------------------------------------------------
42 using namespace NLMISC
;
46 extern CEntityAnimationManager
*EAM
;
49 // ------------------------------------------------------------------------------------------------
51 // ------------------------------------------------------------------------------------------------
53 // ------------------------------------------------------------------------------------------------
54 SCharacter3DSetup::SCharacter3DSetup ()
56 // Setup a naked male fyros
57 LeftHandItemIsShield
= false;
58 People
= EGSPD::CPeople::Fyros
;
60 Skeleton
= "fy_hom_skel.skel";
62 Parts
[Char3DPart_Chest
].Name
= "TR_HOM_underwear_gilet.shape";
63 Parts
[Char3DPart_Legs
].Name
= "FY_HOM_underwear_pantabottes.shape";
64 Parts
[Char3DPart_Arms
].Name
= "TR_HOM_underwear_armpad.shape";
65 Parts
[Char3DPart_Feet
].Name
= "TR_HOM_underwear_bottes.shape";
66 Parts
[Char3DPart_Face
].Name
= "TR_HOM_visage.shape";
67 Parts
[Char3DPart_Head
].Name
= "FY_HOM_cheveux_medium01.shape";
68 Parts
[Char3DPart_Hands
].Name
= "TR_HOM_underwear_hand.shape";
69 Parts
[Char3DPart_HandRightItem
].Name
.clear();
70 Parts
[Char3DPart_HandLeftItem
].Name
.clear();
71 for (uint32 i
= 0; i
< NB_CHARACTER3D_PARTS
; ++i
)
74 Parts
[i
].Quality
= -1;
86 for (uint32 i
= 0; i
< NB_MORPH_TARGETS
; ++i
)
87 MorphTarget
[i
] = 0.0f
;
90 // ------------------------------------------------------------------------------------------------
91 static CGenderInfo
*getGenderInfo (EGSPD::CPeople::TPeople ePeople
, bool bMale
)
93 // Read in the race_stats forms the default equipement
97 case EGSPD::CPeople::Tryker
: RSid
= CSheetId("tryker.race_stats"); break;
98 case EGSPD::CPeople::Matis
: RSid
= CSheetId("matis.race_stats"); break;
99 case EGSPD::CPeople::Zorai
: RSid
= CSheetId("zorai.race_stats"); break;
100 case EGSPD::CPeople::Fyros
:
102 RSid
= CSheetId("fyros.race_stats"); break;
104 CRaceStatsSheet
*pRSS
= dynamic_cast<CRaceStatsSheet
*>(SheetMngr
.get (RSid
));
108 nlwarning ("cannot find sheet for people:%d male:%d", ePeople
, bMale
);
112 // Choose default stuff is we are male or female
115 pGI
= &pRSS
->GenderInfos
[0];
117 pGI
= &pRSS
->GenderInfos
[1];
122 // ------------------------------------------------------------------------------------------------
123 void SCharacter3DSetup::setupDefault (EGSPD::CPeople::TPeople eRace
, bool bMale
)
128 CGenderInfo
*pGI
= getGenderInfo(eRace
, bMale
);
129 if (pGI
== NULL
) return;
131 Skeleton
= pGI
->Skelfilename
;
133 // Read all the default equipement
134 for (sint32 i
= 0; i
< SLOTTYPE::NB_SLOT
; ++i
)
136 string ISstr
= pGI
->Items
[i
]; // All the strings are items
139 CItemSheet
*pIS
= dynamic_cast<CItemSheet
*>(SheetMngr
.get(CSheetId(ISstr
)));
142 sint32 cpIndex
= convert_VisualSlot_To_Char3DPart ((SLOTTYPE::EVisualSlot
)i
);
143 if (cpIndex
!= Char3DPart_INVALID
)
145 Parts
[cpIndex
].Quality
= pIS
->MapVariant
;
147 Parts
[cpIndex
].Name
= pIS
->getShape();
149 Parts
[cpIndex
].Name
= pIS
->getShapeFemale();
156 // ------------------------------------------------------------------------------------------------
157 void SCharacter3DSetup::setupFromCharacterSummary (const CCharacterSummary
&cs
)
159 const SPropVisualA::SPropSubData
&rPVA
= cs
.VisualPropA
.PropertySubData
;
160 const SPropVisualB::SPropSubData
&rPVB
= cs
.VisualPropB
.PropertySubData
;
161 const SPropVisualC::SPropSubData
&rPVC
= cs
.VisualPropC
.PropertySubData
;
163 setupDefault (cs
.People
, (rPVA
.Sex
== 0));
165 // Setup char3dParts with additionnal info
166 setupFromCS_ModelCol (SLOTTYPE::CHEST_SLOT
, rPVA
.JacketModel
, rPVA
.JacketColor
);
167 setupFromCS_ModelCol (SLOTTYPE::LEGS_SLOT
, rPVA
.TrouserModel
, rPVA
.TrouserColor
);
168 setupFromCS_ModelCol (SLOTTYPE::HEAD_SLOT
, rPVA
.HatModel
, rPVA
.HatColor
);
170 // Should have to hide the face ?
172 // TChar3DPart part = convert_VisualSlot_To_Char3DPart (SLOTTYPE::HEAD_SLOT);
173 CItemSheet
*item
= SheetMngr
.getItem (SLOTTYPE::HEAD_SLOT
, rPVA
.HatModel
);
174 if ((item
!= NULL
) && ((item
->Family
== ITEMFAMILY::ARMOR
) || (item
->Family
== ITEMFAMILY::SHIELD
)))
180 setupFromCS_ModelCol (SLOTTYPE::ARMS_SLOT
, rPVA
.ArmModel
, rPVA
.ArmColor
);
181 // setupFromCS_Model (SLOTTYPE::FACE_SLOT, ?????????????);
182 setupFromCS_ModelCol (SLOTTYPE::FEET_SLOT
, rPVB
.FeetModel
, rPVB
.FeetColor
);
183 setupFromCS_ModelCol (SLOTTYPE::RIGHT_HAND_SLOT
, rPVA
.WeaponRightHand
, 0);
184 setupFromCS_ModelCol (SLOTTYPE::LEFT_HAND_SLOT
, rPVA
.WeaponLeftHand
, 0);
185 // armor gloves are not displayed if character has the 'weapon' magician gloves
187 CItemSheet
*item
= SheetMngr
.getItem (SLOTTYPE::RIGHT_HAND_SLOT
, rPVA
.WeaponRightHand
);
188 if( ! ((item
!= NULL
)&&(item
->ItemType
== ITEM_TYPE::MAGICIAN_STAFF
) ) )
189 setupFromCS_ModelCol (SLOTTYPE::HANDS_SLOT
, rPVB
.HandsModel
, rPVB
.HandsColor
);
191 Tattoo
= rPVC
.Tattoo
;
192 HairColor
= rPVA
.HatColor
; // TODO : For the moment no diff between hair color and head color !!!
193 EyesColor
= rPVC
.EyesColor
;
194 CharHeight
= (rPVC
.CharacterHeight
- 7.0f
) / 7.0f
;
195 ChestWidth
= (rPVC
.TorsoWidth
- 7.0f
) / 7.0f
;
196 ArmsWidth
= (rPVC
.ArmsWidth
- 7.0f
) / 7.0f
;
197 LegsWidth
= (rPVC
.LegsWidth
- 7.0f
) / 7.0f
;
198 BreastSize
= (rPVC
.BreastSize
- 7.0f
) / 7.0f
;
201 CGenderInfo
*pGI
= getGenderInfo (cs
.People
, (rPVA
.Sex
== 0));
204 MTmin
= pGI
->BlendShapeMin
[0];
205 MTmax
= pGI
->BlendShapeMax
[0];
206 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
207 MorphTarget
[0] = rPVC
.MorphTarget1
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
208 MTmin
= pGI
->BlendShapeMin
[1];
209 MTmax
= pGI
->BlendShapeMax
[1];
210 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
211 MorphTarget
[1] = rPVC
.MorphTarget2
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
212 MTmin
= pGI
->BlendShapeMin
[2];
213 MTmax
= pGI
->BlendShapeMax
[2];
214 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
215 MorphTarget
[2] = rPVC
.MorphTarget3
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
216 MTmin
= pGI
->BlendShapeMin
[3];
217 MTmax
= pGI
->BlendShapeMax
[3];
218 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
219 MorphTarget
[3] = rPVC
.MorphTarget4
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
220 MTmin
= pGI
->BlendShapeMin
[4];
221 MTmax
= pGI
->BlendShapeMax
[4];
222 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
223 MorphTarget
[4] = rPVC
.MorphTarget5
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
224 MTmin
= pGI
->BlendShapeMin
[5];
225 MTmax
= pGI
->BlendShapeMax
[5];
226 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
227 MorphTarget
[5] = rPVC
.MorphTarget6
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
228 MTmin
= pGI
->BlendShapeMin
[6];
229 MTmax
= pGI
->BlendShapeMax
[6];
230 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
231 MorphTarget
[6] = rPVC
.MorphTarget7
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
232 MTmin
= pGI
->BlendShapeMin
[7];
233 MTmax
= pGI
->BlendShapeMax
[7];
234 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
235 MorphTarget
[7] = rPVC
.MorphTarget8
/ 7.0f
* (MTmax
- MTmin
) + MTmin
;
238 // ------------------------------------------------------------------------------------------------
239 void SCharacter3DSetup::setupFromDataBase (const std::string
&branchName
)
241 CCharacterSummary CS
;
242 setupCharacterSummaryFromDB(CS
, branchName
);
243 setupFromCharacterSummary (CS
);
246 // ------------------------------------------------------------------------------------------------
247 void SCharacter3DSetup::setupFromSERVERDataBase (uint8 nEntity
)
249 CCharacterSummary CS
;
250 setupCharacterSummaryFromSERVERDB(CS
, nEntity
);
251 setupFromCharacterSummary (CS
);
254 // ------------------------------------------------------------------------------------------------
255 void SCharacter3DSetup::setupDBFromCharacterSummary (const string
&branchName
, const CCharacterSummary
&CS
)
257 setDB (branchName
+":PEOPLE", CS
.People
);
259 setDB (branchName
+":VPA:SEX", CS
.VisualPropA
.PropertySubData
.Sex
);
260 setDB (branchName
+":VPA:JACKETMODEL", CS
.VisualPropA
.PropertySubData
.JacketModel
);
261 setDB (branchName
+":VPA:JACKETCOLOR", CS
.VisualPropA
.PropertySubData
.JacketColor
);
262 setDB (branchName
+":VPA:TROUSERMODEL", CS
.VisualPropA
.PropertySubData
.TrouserModel
);
263 setDB (branchName
+":VPA:TROUSERCOLOR", CS
.VisualPropA
.PropertySubData
.TrouserColor
);
264 setDB (branchName
+":VPA:WEAPONRIGHTHAND", CS
.VisualPropA
.PropertySubData
.WeaponRightHand
);
265 setDB (branchName
+":VPA:WEAPONLEFTHAND", CS
.VisualPropA
.PropertySubData
.WeaponLeftHand
);
266 setDB (branchName
+":VPA:ARMMODEL", CS
.VisualPropA
.PropertySubData
.ArmModel
);
267 setDB (branchName
+":VPA:ARMCOLOR", CS
.VisualPropA
.PropertySubData
.ArmColor
);
268 setDB (branchName
+":VPA:HATMODEL", CS
.VisualPropA
.PropertySubData
.HatModel
);
269 setDB (branchName
+":VPA:HATCOLOR", CS
.VisualPropA
.PropertySubData
.HatColor
);
271 setDB (branchName
+":VPB:NAME", CS
.VisualPropB
.PropertySubData
.Name
);
272 setDB (branchName
+":VPB:HANDSMODEL", CS
.VisualPropB
.PropertySubData
.HandsModel
);
273 setDB (branchName
+":VPB:HANDSCOLOR", CS
.VisualPropB
.PropertySubData
.HandsColor
);
274 setDB (branchName
+":VPB:FEETMODEL", CS
.VisualPropB
.PropertySubData
.FeetModel
);
275 setDB (branchName
+":VPB:FEETCOLOR", CS
.VisualPropB
.PropertySubData
.FeetColor
);
277 setDB (branchName
+":VPC:MORPHTARGET1", CS
.VisualPropC
.PropertySubData
.MorphTarget1
);
278 setDB (branchName
+":VPC:MORPHTARGET2", CS
.VisualPropC
.PropertySubData
.MorphTarget2
);
279 setDB (branchName
+":VPC:MORPHTARGET3", CS
.VisualPropC
.PropertySubData
.MorphTarget3
);
280 setDB (branchName
+":VPC:MORPHTARGET4", CS
.VisualPropC
.PropertySubData
.MorphTarget4
);
281 setDB (branchName
+":VPC:MORPHTARGET5", CS
.VisualPropC
.PropertySubData
.MorphTarget5
);
282 setDB (branchName
+":VPC:MORPHTARGET6", CS
.VisualPropC
.PropertySubData
.MorphTarget6
);
283 setDB (branchName
+":VPC:MORPHTARGET7", CS
.VisualPropC
.PropertySubData
.MorphTarget7
);
284 setDB (branchName
+":VPC:MORPHTARGET8", CS
.VisualPropC
.PropertySubData
.MorphTarget8
);
285 setDB (branchName
+":VPC:EYESCOLOR", CS
.VisualPropC
.PropertySubData
.EyesColor
);
286 setDB (branchName
+":VPC:TATTOO", CS
.VisualPropC
.PropertySubData
.Tattoo
);
287 setDB (branchName
+":VPC:CHARACTERHEIGHT", CS
.VisualPropC
.PropertySubData
.CharacterHeight
);
288 setDB (branchName
+":VPC:TORSOWIDTH", CS
.VisualPropC
.PropertySubData
.TorsoWidth
);
289 setDB (branchName
+":VPC:ARMSWIDTH", CS
.VisualPropC
.PropertySubData
.ArmsWidth
);
290 setDB (branchName
+":VPC:LEGSWIDTH", CS
.VisualPropC
.PropertySubData
.LegsWidth
);
291 setDB (branchName
+":VPC:BREASTSIZE", CS
.VisualPropC
.PropertySubData
.BreastSize
);
294 // ------------------------------------------------------------------------------------------------
295 void SCharacter3DSetup::setupCharacterSummaryFromDB (CCharacterSummary
&CS
, const string
&branchName
)
297 CS
.People
= (EGSPD::CPeople::TPeople
)getDB (branchName
+":PEOPLE");
299 CS
.VisualPropA
.PropertySubData
.Sex
= getDB (branchName
+":VPA:SEX");
300 CS
.VisualPropA
.PropertySubData
.JacketModel
= getDB (branchName
+":VPA:JACKETMODEL");
301 CS
.VisualPropA
.PropertySubData
.JacketColor
= getDB (branchName
+":VPA:JACKETCOLOR");
302 CS
.VisualPropA
.PropertySubData
.TrouserModel
= getDB (branchName
+":VPA:TROUSERMODEL");
303 CS
.VisualPropA
.PropertySubData
.TrouserColor
= getDB (branchName
+":VPA:TROUSERCOLOR");
304 CS
.VisualPropA
.PropertySubData
.WeaponRightHand
= getDB (branchName
+":VPA:WEAPONRIGHTHAND");
305 CS
.VisualPropA
.PropertySubData
.WeaponLeftHand
= getDB (branchName
+":VPA:WEAPONLEFTHAND");
306 CS
.VisualPropA
.PropertySubData
.ArmModel
= getDB (branchName
+":VPA:ARMMODEL");
307 CS
.VisualPropA
.PropertySubData
.ArmColor
= getDB (branchName
+":VPA:ARMCOLOR");
308 CS
.VisualPropA
.PropertySubData
.HatModel
= getDB (branchName
+":VPA:HATMODEL");
309 CS
.VisualPropA
.PropertySubData
.HatColor
= getDB (branchName
+":VPA:HATCOLOR");
311 CS
.VisualPropB
.PropertySubData
.Name
= getDB (branchName
+":VPB:NAME");
312 CS
.VisualPropB
.PropertySubData
.HandsModel
= getDB (branchName
+":VPB:HANDSMODEL");
313 CS
.VisualPropB
.PropertySubData
.HandsColor
= getDB (branchName
+":VPB:HANDSCOLOR");
314 CS
.VisualPropB
.PropertySubData
.FeetModel
= getDB (branchName
+":VPB:FEETMODEL");
315 CS
.VisualPropB
.PropertySubData
.FeetColor
= getDB (branchName
+":VPB:FEETCOLOR");
317 CS
.VisualPropC
.PropertySubData
.MorphTarget1
= getDB (branchName
+":VPC:MORPHTARGET1");
318 CS
.VisualPropC
.PropertySubData
.MorphTarget2
= getDB (branchName
+":VPC:MORPHTARGET2");
319 CS
.VisualPropC
.PropertySubData
.MorphTarget3
= getDB (branchName
+":VPC:MORPHTARGET3");
320 CS
.VisualPropC
.PropertySubData
.MorphTarget4
= getDB (branchName
+":VPC:MORPHTARGET4");
321 CS
.VisualPropC
.PropertySubData
.MorphTarget5
= getDB (branchName
+":VPC:MORPHTARGET5");
322 CS
.VisualPropC
.PropertySubData
.MorphTarget6
= getDB (branchName
+":VPC:MORPHTARGET6");
323 CS
.VisualPropC
.PropertySubData
.MorphTarget7
= getDB (branchName
+":VPC:MORPHTARGET7");
324 CS
.VisualPropC
.PropertySubData
.MorphTarget8
= getDB (branchName
+":VPC:MORPHTARGET8");
325 CS
.VisualPropC
.PropertySubData
.EyesColor
= getDB (branchName
+":VPC:EYESCOLOR");
326 CS
.VisualPropC
.PropertySubData
.Tattoo
= getDB (branchName
+":VPC:TATTOO");
327 CS
.VisualPropC
.PropertySubData
.CharacterHeight
= getDB (branchName
+":VPC:CHARACTERHEIGHT");
328 CS
.VisualPropC
.PropertySubData
.TorsoWidth
= getDB (branchName
+":VPC:TORSOWIDTH");
329 CS
.VisualPropC
.PropertySubData
.ArmsWidth
= getDB (branchName
+":VPC:ARMSWIDTH");
330 CS
.VisualPropC
.PropertySubData
.LegsWidth
= getDB (branchName
+":VPC:LEGSWIDTH");
331 CS
.VisualPropC
.PropertySubData
.BreastSize
= getDB (branchName
+":VPC:BREASTSIZE");
334 // ------------------------------------------------------------------------------------------------
336 void SCharacter3DSetup::setupCharacterSummaryFromSERVERDB (CCharacterSummary
&cs
, uint8 entityID
)
340 cs
.VisualPropA
= getDB ("SERVER:Entities:E"+NLMISC::toString(entityID
)+
341 ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPA
));
343 cs
.VisualPropB
= getDB ("SERVER:Entities:E"+NLMISC::toString(entityID
)+
344 ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPB
));
346 cs
.VisualPropC
= getDB ("SERVER:Entities:E"+NLMISC::toString(entityID
)+
347 ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPC
));
349 cs
.People
= EGSPD::CPeople::Fyros
;
350 CPlayerCL
*pp
= NULL
;
352 if ((pp
=dynamic_cast<CPlayerCL
*>(EntitiesMngr
.entity(entityID
))) == NULL
)
354 pp
=(CPlayerCL
*)dynamic_cast<CPlayerR2CL
*>(EntitiesMngr
.entity(entityID
));
358 cs
.People
= pp
->people();
359 cs
.VisualPropA
.PropertySubData
.Sex
= (pp
->getGender() == GSGENDER::female
);
363 // ------------------------------------------------------------------------------------------------
364 TChar3DPart
SCharacter3DSetup::convert_VisualSlot_To_Char3DPart (SLOTTYPE::EVisualSlot vs
)
368 case SLOTTYPE::HIDDEN_SLOT
: return Char3DPart_INVALID
;
369 case SLOTTYPE::CHEST_SLOT
: return Char3DPart_Chest
;
370 case SLOTTYPE::LEGS_SLOT
: return Char3DPart_Legs
;
371 case SLOTTYPE::HEAD_SLOT
: return Char3DPart_Head
;
372 case SLOTTYPE::ARMS_SLOT
: return Char3DPart_Arms
;
373 case SLOTTYPE::FACE_SLOT
: return Char3DPart_Face
;
374 case SLOTTYPE::HANDS_SLOT
: return Char3DPart_Hands
;
375 case SLOTTYPE::FEET_SLOT
: return Char3DPart_Feet
;
376 case SLOTTYPE::RIGHT_HAND_SLOT
: return Char3DPart_HandRightItem
;
377 case SLOTTYPE::LEFT_HAND_SLOT
: return Char3DPart_HandLeftItem
;
378 case SLOTTYPE::NB_SLOT
: return Char3DPart_INVALID
;
381 return Char3DPart_INVALID
;
384 // ------------------------------------------------------------------------------------------------
385 SLOTTYPE::EVisualSlot
SCharacter3DSetup::convert_Char3DPart_To_VisualSlot (TChar3DPart cp
)
389 case Char3DPart_Chest
: return SLOTTYPE::CHEST_SLOT
;
390 case Char3DPart_Legs
: return SLOTTYPE::LEGS_SLOT
;
391 case Char3DPart_Head
: return SLOTTYPE::HEAD_SLOT
;
392 case Char3DPart_Arms
: return SLOTTYPE::ARMS_SLOT
;
393 case Char3DPart_Face
: return SLOTTYPE::FACE_SLOT
;
394 case Char3DPart_Hands
: return SLOTTYPE::HANDS_SLOT
;
395 case Char3DPart_Feet
: return SLOTTYPE::FEET_SLOT
;
396 case Char3DPart_HandRightItem
: return SLOTTYPE::RIGHT_HAND_SLOT
;
397 case Char3DPart_HandLeftItem
: return SLOTTYPE::LEFT_HAND_SLOT
;
398 case Char3DPart_INVALID
: return SLOTTYPE::NB_SLOT
;
401 return SLOTTYPE::HIDDEN_SLOT
;
404 // ------------------------------------------------------------------------------------------------
405 string
SCharacter3DSetup::convert_VisualSlot_To_String (SLOTTYPE::EVisualSlot vs
)
409 case SLOTTYPE::HIDDEN_SLOT
: return string("Hidden");
410 case SLOTTYPE::CHEST_SLOT
: return string("Chest");
411 case SLOTTYPE::LEGS_SLOT
: return string("Legs");
412 case SLOTTYPE::HEAD_SLOT
: return string("Head");
413 case SLOTTYPE::ARMS_SLOT
: return string("Arms");
414 case SLOTTYPE::FACE_SLOT
: return string("Face");
415 case SLOTTYPE::HANDS_SLOT
: return string("Hands");
416 case SLOTTYPE::FEET_SLOT
: return string("Feet");
417 case SLOTTYPE::RIGHT_HAND_SLOT
: return string("Hand Right Item");
418 case SLOTTYPE::LEFT_HAND_SLOT
: return string("Hand Left Item");
419 case SLOTTYPE::NB_SLOT
: return string("Number Of Slot");
422 return string("Invalid");
425 // ------------------------------------------------------------------------------------------------
426 void SCharacter3DSetup::setupFromCS_ModelCol (SLOTTYPE::EVisualSlot s
, sint32 model
, sint32 col
)
428 TChar3DPart part
= convert_VisualSlot_To_Char3DPart (s
);
429 if (part
== Char3DPart_INVALID
) return;
431 CItemSheet
*item
= SheetMngr
.getItem (s
, model
);
434 // magician gloves are a weapon but displayed in hands slot(armor gloves)
435 if( (s
== SLOTTYPE::RIGHT_HAND_SLOT
) && (item
->ItemType
== ITEM_TYPE::MAGICIAN_STAFF
) )
437 Parts
[part
].Name
= "none.shape";
438 part
= convert_VisualSlot_To_Char3DPart (SLOTTYPE::HANDS_SLOT
);
441 Parts
[part
].Quality
= item
->MapVariant
;
446 case EGSPD::CPeople::Fyros
:
447 Parts
[part
].Name
= item
->getShapeFyros();
449 case EGSPD::CPeople::Matis
:
450 Parts
[part
].Name
= item
->getShapeMatis();
452 case EGSPD::CPeople::Tryker
:
453 Parts
[part
].Name
= item
->getShapeTryker();
455 case EGSPD::CPeople::Zorai
:
456 Parts
[part
].Name
= item
->getShapeZorai();
459 if (Parts
[part
].Name
.empty())
460 Parts
[part
].Name
= item
->getShape();
466 case EGSPD::CPeople::Fyros
:
467 Parts
[part
].Name
= item
->getShapeFyrosFemale();
469 case EGSPD::CPeople::Matis
:
470 Parts
[part
].Name
= item
->getShapeMatisFemale();
472 case EGSPD::CPeople::Tryker
:
473 Parts
[part
].Name
= item
->getShapeTrykerFemale();
475 case EGSPD::CPeople::Zorai
:
476 Parts
[part
].Name
= item
->getShapeZoraiFemale();
479 if (Parts
[part
].Name
.empty())
480 Parts
[part
].Name
= item
->getShapeFemale();
483 // use the right type of boots if wearing a caster dress
484 if ((s
== SLOTTYPE::FEET_SLOT
) && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
|| item
->ItemType
== ITEM_TYPE::MEDIUM_BOOTS
|| item
->ItemType
== ITEM_TYPE::HEAVY_BOOTS
))
486 std::string shapeLegs
= Parts
[Char3DPart_Legs
].Name
;
488 if (shapeLegs
.find("_caster01_") != std::string::npos
)
490 std::string tmpName
= toLowerAscii(Parts
[part
].Name
);
492 std::string::size_type posBottes
= tmpName
.find("_bottes");
494 if (posBottes
!= std::string::npos
)
496 std::string orgType
= tmpName
.substr(7, posBottes
-7); // underwear, caster01, armor00 or armor01
498 tmpName
.replace(posBottes
+7, 0, "_" + orgType
);
499 tmpName
.replace(7, orgType
.length(), "caster01");
501 if (CPath::exists(tmpName
))
503 // use fixed shape name only if file is present
504 Parts
[part
].Name
= tmpName
;
508 // temporary hack because Fyros light boots don't respect conventions
509 if (tmpName
[0] == 'f' && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
))
511 if (tmpName
[5] == 'f')
513 tmpName
= "fy_hof_caster01_bottes_civil.shape";
517 tmpName
= "fy_hom_caster01_civil01_bottes.shape";
520 // use fixed shape name only if file is present
521 if (CPath::exists(tmpName
))
523 Parts
[part
].Name
= tmpName
;
527 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), Parts
[part
].Name
.c_str());
532 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), Parts
[part
].Name
.c_str());
541 Parts
[part
].AdvFx
= item
->FX
.getAdvantageFX();
542 Parts
[part
].StatFxNames
.clear();
543 Parts
[part
].StatFxBones
.clear();
544 Parts
[part
].StatFxOffss
.clear();
545 for (uint32 fx
= 0; fx
< item
->FX
.getNumStaticFX(); ++fx
)
547 Parts
[part
].StatFxNames
.push_back(item
->FX
.getStaticFXName(fx
));
548 Parts
[part
].StatFxBones
.push_back(item
->FX
.getStaticFXBone(fx
));
549 Parts
[part
].StatFxOffss
.push_back(item
->FX
.getStaticFXOffset(fx
));
553 if (part
== Char3DPart_HandLeftItem
)
555 if ((item
->ItemType
== ITEM_TYPE::SHIELD
) || (item
->ItemType
== ITEM_TYPE::BUCKLER
))
556 LeftHandItemIsShield
= true;
558 LeftHandItemIsShield
= false;
563 // fix underwears color
564 if (model
== 0) col
= 6; // white
566 if ((part
== Char3DPart_HandLeftItem
) || (part
== Char3DPart_HandRightItem
))
567 Parts
[part
].Name
= "none.shape";
570 Parts
[part
].Color
= col
;
573 // ------------------------------------------------------------------------------------------------
574 uint64
SCharacter3DSetup::getDB (const string
&name
)
576 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
577 CCDBNodeLeaf
*pNL
= NLGUI::CDBManager::getInstance()->getDbProp(name
);
578 if (pNL
== NULL
) return 0;
579 return pNL
->getValue64();
582 // ------------------------------------------------------------------------------------------------
583 void SCharacter3DSetup::setDB (const string
&name
, uint64 val
)
585 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
586 CCDBNodeLeaf
*pNL
= NLGUI::CDBManager::getInstance()->getDbProp(name
);
587 if (pNL
== NULL
) return;
588 pNL
->setValue64(val
);
591 // ------------------------------------------------------------------------------------------------
592 void DEBUG_DumpClothes()
594 for (uint cp
= 0; cp
< NB_CHARACTER3D_PARTS
; ++cp
)
595 if (cp
!= Char3DPart_Face
)
597 SLOTTYPE::EVisualSlot vs
= SCharacter3DSetup::convert_Char3DPart_To_VisualSlot((TChar3DPart
)cp
);
598 string sTmp
= SCharacter3DSetup::convert_VisualSlot_To_String(vs
);
599 nlinfo("*** PART *** : %s", sTmp
.c_str());
601 if (cp
== Char3DPart_HandRightItem
)
603 if ((cp
== Char3DPart_Chest
) || (cp
== Char3DPart_Hands
) || (cp
== Char3DPart_Feet
))
605 if ((cp
== Char3DPart_Legs
) || (cp
== Char3DPart_Arms
) || (cp
== Char3DPart_HandLeftItem
))
607 if (cp
== Char3DPart_Head
)
609 for (uint it
= 0; it
< nNbItems
; ++it
)
611 CItemSheet
*item
= SheetMngr
.getItem (vs
, it
);
614 //nlinfo(" val:%d UNKNOWN",it);
618 //nlinfo(" val:%d M[%s] F[%s]", it, item->Shape.c_str(), item->ShapeFemale.c_str());
619 const CSheetManager::TEntitySheetMap
&esm
= SheetMngr
.getSheets();
620 CSheetManager::TEntitySheetMap::const_iterator esmit
= esm
.begin();
621 while (esmit
!= esm
.end())
623 if (esmit
->second
.EntitySheet
== item
)
625 nlinfo(" val:%d item[%s]", it
, esmit
->first
.toString().c_str() );
637 // ------------------------------------------------------------------------------------------------
639 // ------------------------------------------------------------------------------------------------
641 // ------------------------------------------------------------------------------------------------
643 CCharacter3D::CCharacter3D()
645 _ClusterSystem
= NULL
;
647 _PlayListManager
= NULL
;
648 _AnimationSet
= NULL
;
650 _FacePlayList
= NULL
;
651 // Clear the cache to make it work with 1st init
652 _CurrentSetup
.Skeleton
.clear();
653 _CurrentSetup
.AnimPlayed
= -1;
654 for (uint32 i
= 0; i
< NB_CHARACTER3D_PARTS
; ++i
)
656 _CurrentSetup
.Parts
[i
].Name
.clear();
657 _CurrentSetup
.Parts
[i
].Color
= -1;
658 _CurrentSetup
.Parts
[i
].Quality
= -1;
660 _CurrentSetup
.Tattoo
= -1;
661 _CurrentSetup
.EyesColor
= -1;
662 _CurrentSetup
.CharHeight
= _CurrentSetup
.ChestWidth
= -20.0f
;
663 _CurrentSetup
.ArmsWidth
= _CurrentSetup
.LegsWidth
= _CurrentSetup
.BreastSize
= -20.0f
;
664 _PelvisPos
.set(0.f
,0.f
,-20.0f
);
665 _CurPosX
= _CurPosY
= _CurPosZ
= 0.0f
;
666 _CurRotX
= _CurRotY
= _CurRotZ
= 0.0f
;
671 // ------------------------------------------------------------------------------------------------
672 CCharacter3D::~CCharacter3D()
674 if (_Scene
== NULL
) return;
676 // Delete animations first
677 if (_PlayListManager
!= NULL
)
679 if (_PlayList
!= NULL
)
681 _PlayList
->resetAllChannels();
682 _PlayListManager
->deletePlayList(_PlayList
);
684 if (_FacePlayList
!= NULL
)
686 _FacePlayList
->resetAllChannels();
687 _PlayListManager
->deletePlayList(_FacePlayList
);
689 _Scene
->deletePlayListManager(_PlayListManager
);
694 for (uint32 i
= 0; i
< NB_CHARACTER3D_PARTS
; ++i
)
696 if (!_Instances
[i
].empty())
697 _Scene
->deleteInstance (_Instances
[i
]);
699 for (uint32 fx
= 0; fx
< _InstancesFx
[i
].StaticFx
.size(); ++fx
)
700 if (!_InstancesFx
[i
].StaticFx
[fx
].empty())
701 _Scene
->deleteInstance(_InstancesFx
[i
].StaticFx
[fx
]);
702 _InstancesFx
[i
].StaticFx
.clear();
704 if (!_InstancesFx
[i
].AdvantageFx
.empty())
705 _Scene
->deleteInstance (_InstancesFx
[i
].AdvantageFx
);
708 if(!_Skeleton
.empty())
709 _Scene
->deleteSkeleton(_Skeleton
);
714 // ------------------------------------------------------------------------------------------------
715 bool CCharacter3D::init (UScene
*pScene
)
717 // DEBUG_DumpClothes();
719 if (_Scene
!= NULL
) return true;
722 _PlayListManager
= _Scene
->createPlayListManager();
723 if (!_PlayListManager
)
725 nlwarning ("CCharacter3D : couldn't create playlist manager");
731 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
732 COptionsAnimationSet
*pOAS
= dynamic_cast<COptionsAnimationSet
*>(CWidgetManager::getInstance()->getOptions("character_animations"));
733 if(!pOAS
|| !pOAS
->AnimationSet
)
735 nlwarning("Not found <options> 'character_animations', or not of type 'animation_set'");
739 if(ClientCfg
.Light
|| !ClientCfg
.EAMEnabled
)
742 // Retrieve the animation info
745 resetAnimation (pOAS
->AnimationSet
);
746 _AnimMale
= pOAS
->AnimMale
;
747 _AnimFemale
= pOAS
->AnimFemale
;
753 resetAnimation (EAM
->getAnimationSet());
760 // ------------------------------------------------------------------------------------------------
761 void CCharacter3D::resetAnimation (UAnimationSet
*animSet
)
766 _PlayList
->resetAllChannels();
768 _FacePlayList
->resetAllChannels();
769 // if (_PlayList != NULL) _PlayListManager->deletePlayList (_PlayList);
770 // if (_FacePlayList != NULL) _PlayListManager->deletePlayList (_FacePlayList);
772 _AnimationSet
= animSet
;
774 if (_PlayList
== NULL
)
775 _PlayList
= _PlayListManager
->createPlayList(_AnimationSet
);
778 nlwarning ("CCharacter3D : couldn't create play list");
779 _Scene
->deletePlayListManager (_PlayListManager
);
780 _PlayListManager
= NULL
;
781 _AnimationSet
= NULL
;
785 if (_FacePlayList
== NULL
)
786 _FacePlayList
= _PlayListManager
->createPlayList (_AnimationSet
);
789 nlwarning ("CCharacter3D : couldn't create face play list");
790 // no face anim, but body anim is still available
795 // ------------------------------------------------------------------------------------------------
796 void CCharacter3D::disableFaceMorphAndBlinks()
798 if(_FacePlayList
&& _AnimationSet
)
800 // disable eye blink animation (handled by ourselves)
801 uint id
= _AnimationSet
->getChannelIdByName("visage_100MorphFactor");
802 if(id
!=UAnimationSet::NotFound
)
803 _FacePlayList
->enableChannel(id
, false);
804 // disable morph target (handled by ourselves)
805 for(uint i
=0;i
<NB_MORPH_TARGETS
;i
++)
807 static const string baseName
= "visage_00";
808 id
= _AnimationSet
->getChannelIdByName(baseName
+ toString(i
) + "MorphFactor");
809 if(id
!=UAnimationSet::NotFound
)
810 _FacePlayList
->enableChannel(id
, false);
815 // ------------------------------------------------------------------------------------------------
816 void CCharacter3D::setup (const SCharacter3DSetup
&c3ds
)
818 bool bSkeletonRebuilt
= false;
819 // Test with cache and call dressing/loading functions
820 if (!c3ds
.Skeleton
.empty())
821 if (c3ds
.Skeleton
!= _CurrentSetup
.Skeleton
)
823 setSkeleton (c3ds
.Skeleton
);
824 _CurrentSetup
.Skeleton
= c3ds
.Skeleton
;
825 bSkeletonRebuilt
= true;
826 _Skeleton
.setClusterSystem (_ClusterSystem
);
829 _PlayList
->registerTransform (_Skeleton
);
830 // disable pos animation
831 uint id
= _AnimationSet
->getChannelIdByName("pos");
832 if(id
!=UAnimationSet::NotFound
)
833 _PlayList
->enableChannel(id
, false);
837 // Information that are additionnal
838 _CurrentSetup
.LeftHandItemIsShield
= c3ds
.LeftHandItemIsShield
;
839 _CurrentSetup
.Male
= c3ds
.Male
;
844 for (i
= 0; i
< NB_CHARACTER3D_PARTS
; ++i
)
846 bool bInstanceRebuilt
= false;
847 bool bQualityRebuilt
= false;
850 if ((c3ds
.Parts
[i
].Name
!= _CurrentSetup
.Parts
[i
].Name
) || (c3ds
.Parts
[i
].AdvFx
!= _CurrentSetup
.Parts
[i
].AdvFx
))
852 // If face, unregister FacePlayList
853 if(i
==Char3DPart_Face
&& _FacePlayList
)
854 _FacePlayList
->resetAllChannels();
856 // rebuild this instance
857 bInstanceRebuilt
= true;
858 createInstance ((TChar3DPart
)i
, c3ds
.Parts
[i
]);
859 _CurrentSetup
.Parts
[i
].Name
= c3ds
.Parts
[i
].Name
;
860 _CurrentSetup
.Parts
[i
].AdvFx
= c3ds
.Parts
[i
].AdvFx
;
861 _CurrentSetup
.Parts
[i
].StatFxNames
= c3ds
.Parts
[i
].StatFxNames
;
862 _CurrentSetup
.Parts
[i
].StatFxBones
= c3ds
.Parts
[i
].StatFxBones
;
863 _CurrentSetup
.Parts
[i
].StatFxOffss
= c3ds
.Parts
[i
].StatFxOffss
;
865 // If face and instance created, reassign FacePlayList
866 if(i
==Char3DPart_Face
&& _FacePlayList
&& !_Instances
[Char3DPart_Face
].empty())
868 _FacePlayList
->registerTransform(_Instances
[Char3DPart_Face
]);
869 disableFaceMorphAndBlinks();
874 if (c3ds
.Parts
[i
].Quality
!= -1)
875 if ((c3ds
.Parts
[i
].Quality
!= _CurrentSetup
.Parts
[i
].Quality
) || bInstanceRebuilt
)
877 if (!_Instances
[i
].empty())
879 _Instances
[i
].selectTextureSet((uint
)c3ds
.Parts
[i
].Quality
);
880 bQualityRebuilt
= true;
882 _CurrentSetup
.Parts
[i
].Quality
= c3ds
.Parts
[i
].Quality
;
885 // Instance user color
886 if (c3ds
.Parts
[i
].Color
!= -1)
887 if ((c3ds
.Parts
[i
].Color
!= _CurrentSetup
.Parts
[i
].Color
) || bInstanceRebuilt
|| bQualityRebuilt
)
889 if (!_Instances
[i
].empty())
891 ColorSlotManager
.setInstanceSlot ( _Instances
[i
],
892 1u, // Slot 1 is for user color
893 c3ds
.Parts
[i
].Color
);
895 _CurrentSetup
.Parts
[i
].Color
= c3ds
.Parts
[i
].Color
;
898 // Instance skin color
899 if (c3ds
.People
!= EGSPD::CPeople::Undefined
)
900 if ((c3ds
.People
!= _CurrentSetup
.People
) || bInstanceRebuilt
|| bQualityRebuilt
)
902 if (!_Instances
[i
].empty() && i
!= Char3DPart_HandRightItem
&& i
!= Char3DPart_HandLeftItem
)
904 ColorSlotManager
.setInstanceSlot ( _Instances
[i
],
905 0u, // Slot 0 is for skin
906 peopleToSkin(c3ds
.People
));
908 // Here we do not update current setup people value to let other instances colorize too
914 case Char3DPart_Face
:
916 if (c3ds
.Tattoo
!= -1)
917 if ((c3ds
.Tattoo
!= _CurrentSetup
.Tattoo
) || bInstanceRebuilt
)
919 if (!_Instances
[Char3DPart_Face
].empty())
920 makeUp (_Instances
[Char3DPart_Face
], c3ds
.Tattoo
);
921 _CurrentSetup
.Tattoo
= c3ds
.Tattoo
;
924 if (c3ds
.EyesColor
!= -1)
925 if ((c3ds
.EyesColor
!= _CurrentSetup
.EyesColor
) ||bInstanceRebuilt
)
927 if (!_Instances
[Char3DPart_Face
].empty())
928 ColorSlotManager
.setInstanceSlot ( _Instances
[Char3DPart_Face
],
929 (uint
)3, // slot 3 is for eyes colors
931 _CurrentSetup
.EyesColor
= c3ds
.EyesColor
;
933 // Setup morph targets
934 if ((c3ds
.MorphTarget
[0] != _CurrentSetup
.MorphTarget
[0]) ||
935 (c3ds
.MorphTarget
[1] != _CurrentSetup
.MorphTarget
[1]) ||
936 (c3ds
.MorphTarget
[2] != _CurrentSetup
.MorphTarget
[2]) ||
937 (c3ds
.MorphTarget
[3] != _CurrentSetup
.MorphTarget
[3]) ||
938 (c3ds
.MorphTarget
[4] != _CurrentSetup
.MorphTarget
[4]) ||
939 (c3ds
.MorphTarget
[5] != _CurrentSetup
.MorphTarget
[5]) ||
940 (c3ds
.MorphTarget
[6] != _CurrentSetup
.MorphTarget
[6]) ||
941 (c3ds
.MorphTarget
[7] != _CurrentSetup
.MorphTarget
[7]) ||
942 bInstanceRebuilt
|| bSkeletonRebuilt
)
944 if (!_Instances
[Char3DPart_Face
].empty())
946 for(uint k
= 0; k
< NB_MORPH_TARGETS
; ++k
)
948 static const char *baseName
= "visage_00";
949 _Instances
[Char3DPart_Face
].setBlendShapeFactor (baseName
+ toString(k
),
950 c3ds
.MorphTarget
[k
], true);
951 _CurrentSetup
.MorphTarget
[k
] = c3ds
.MorphTarget
[k
];
956 if (!_Instances
[Char3DPart_Face
].empty())
959 _Instances
[Char3DPart_Face
].hide();
961 _Instances
[Char3DPart_Face
].show();
964 _CurrentSetup
.HideFace
= c3ds
.HideFace
;
966 // Setup hair color (for both part)
967 if (c3ds
.HairColor
!= -1)
968 if ((c3ds
.HairColor
!= _CurrentSetup
.HairColor
) || bInstanceRebuilt
)
970 if (!_Instances
[Char3DPart_Face
].empty())
971 ColorSlotManager
.setInstanceSlot ( _Instances
[Char3DPart_Face
],
972 (uint
)2, // slot 2 is for hair color
974 //_CurrentSetup.HairColor = c3ds.HairColor;
977 case Char3DPart_Head
:
979 if (c3ds
.HairColor
!= -1)
980 if ((c3ds
.HairColor
!= _CurrentSetup
.HairColor
) || bInstanceRebuilt
)
982 if (!_Instances
[Char3DPart_Head
].empty())
983 ColorSlotManager
.setInstanceSlot ( _Instances
[Char3DPart_Head
],
984 (uint
)2, // slot 2 is for hair color
986 _CurrentSetup
.HairColor
= c3ds
.HairColor
;
993 // Bind instance to skeleton
994 if (bInstanceRebuilt
|| bSkeletonRebuilt
)
996 bindToSkeleton ((TChar3DPart
)i
);
999 _CurrentSetup
.People
= c3ds
.People
; // Because not done for each instance
1002 bool bGabaritChanged
= false;
1003 if ((c3ds
.CharHeight
!= _CurrentSetup
.CharHeight
) ||
1004 (c3ds
.ChestWidth
!= _CurrentSetup
.ChestWidth
) ||
1005 (c3ds
.ArmsWidth
!= _CurrentSetup
.ArmsWidth
) ||
1006 (c3ds
.LegsWidth
!= _CurrentSetup
.LegsWidth
) ||
1007 (c3ds
.BreastSize
!= _CurrentSetup
.BreastSize
) ||
1011 uint gender
= _CurrentSetup
.Male
? 0 : 1;
1013 GabaritSet
.applyGabarit ( _Skeleton
, gender
, _CurrentSetup
.People
,
1014 c3ds
.CharHeight
, c3ds
.ChestWidth
, c3ds
.ArmsWidth
, c3ds
.LegsWidth
, c3ds
.BreastSize
,
1016 float refHeightScale
= GabaritSet
.getRefHeightScale(gender
, _CurrentSetup
.People
);
1017 // dummy code, to avoid 1 frame big swap
1018 _PelvisPos
.z
= 1.f
* heightScale
;
1020 _CurrentSetup
.CharHeight
= c3ds
.CharHeight
;
1021 _CurrentSetup
.ChestWidth
= c3ds
.ChestWidth
;
1022 _CurrentSetup
.ArmsWidth
= c3ds
.ArmsWidth
;
1023 _CurrentSetup
.LegsWidth
= c3ds
.LegsWidth
;
1024 _CurrentSetup
.BreastSize
= c3ds
.BreastSize
;
1026 if(refHeightScale
!= 0.f
)
1027 _CustomScalePos
= heightScale
/refHeightScale
;
1029 _CustomScalePos
= 1.f
;
1031 bGabaritChanged
= true;
1034 // Play an animation
1036 if (c3ds
.AnimPlayed
!= -1)
1037 if ((c3ds
.AnimPlayed
!= _CurrentSetup
.AnimPlayed
) || (bSkeletonRebuilt
) || _CopyAnim
)
1038 setAnim (c3ds
.AnimPlayed
);
1040 if (bSkeletonRebuilt
|| bGabaritChanged
)
1043 // If skeleton or gabarit has changed replace correctly the skeleton from feet reference point
1044 setPos (_CurPosX
, _CurPosY
, _CurPosZ
);
1045 setRotEuler (_CurRotX
, _CurRotY
, _CurRotZ
);
1047 // update skeleton pelvis pos
1048 if (!_Skeleton
.empty())
1049 _Skeleton
.setPos(_PelvisPos
);
1052 // ------------------------------------------------------------------------------------------------
1053 void CCharacter3D::setAnim (uint animID
)
1055 CCharacterCL
* character
= NULL
;
1059 _CurrentSetup
.AnimPlayed
= animID
;
1060 if (_CurrentSetup
.Male
)
1062 if (animID
>= _AnimMale
.size()) return;
1063 animID
= _AnimMale
[animID
].AnimId
;
1067 if (animID
>= _AnimFemale
.size()) return;
1068 animID
= _AnimFemale
[animID
].AnimId
;
1073 CInstance
* selectedInst
= getEditor().getSelectedInstance();
1074 if(!selectedInst
) return;
1075 CEntityCL
* entity
= selectedInst
->getEntity();
1076 if(!(entity
&& ((character
=dynamic_cast<CCharacterCL
*>(entity
))!=NULL
)))
1079 animID
= character
->playList()->getAnimation(MOVE
);
1080 _CurrentSetup
.AnimPlayed
= animID
;
1084 float animSpeedFactor
= 0.9f
+ 0.2f
* NLMISC::frand(1);
1089 _PlayList
->setTimeOrigin(MOVE
, character
->playList()->getTimeOrigin(MOVE
));
1090 if(character
->playList()->getAnimation(MOVE
)!=_PlayList
->getAnimation(MOVE
))
1092 _PlayList
->setAnimation(MOVE
, animID
);
1093 _PlayList
->setSpeedFactor(MOVE
, character
->playList()->getSpeedFactor(MOVE
));
1094 _PlayList
->setWrapMode(MOVE
, character
->playList()->getWrapMode(MOVE
));
1099 _PlayList
->setAnimation(MOVE
, animID
);
1100 _PlayList
->setSpeedFactor(MOVE
, animSpeedFactor
);
1101 _PlayList
->setTimeOrigin(MOVE
, TimeInSec
);
1102 _PlayList
->setWrapMode(MOVE
, UPlayList::Repeat
);
1108 uint faceAnimId
=UPlayList::empty
;
1109 if(_AnimationSet
&& animID
<_AnimationSet
->getNumAnimation())
1111 // build the anim name of the face
1112 string faceAnimName
= COptionsAnimationSet::getFaceAnimName(_AnimationSet
->getAnimationName(animID
));
1113 // find the face anim for this name
1114 faceAnimId
= _AnimationSet
->getAnimationIdByName(faceAnimName
);
1115 if(faceAnimId
==UAnimationSet::NotFound
)
1116 faceAnimId
= UPlayList::empty
;
1119 _FacePlayList
->setAnimation(MOVE
, faceAnimId
);
1120 if(faceAnimId
!=UPlayList::empty
)
1124 _FacePlayList
->setTimeOrigin(MOVE
, character
->facePlayList()->getTimeOrigin(MOVE
));
1125 _FacePlayList
->setSpeedFactor(MOVE
, character
->facePlayList()->getSpeedFactor(MOVE
));
1126 _FacePlayList
->setWrapMode(MOVE
, character
->facePlayList()->getWrapMode(MOVE
));
1130 _FacePlayList
->setSpeedFactor(MOVE
, animSpeedFactor
);
1131 _FacePlayList
->setTimeOrigin(MOVE
, TimeInSec
);
1132 _FacePlayList
->setWrapMode(MOVE
, UPlayList::Repeat
);
1138 // ------------------------------------------------------------------------------------------------
1139 void CCharacter3D::animate (double globalTime
)
1141 if (!_AnimationSet
) return;
1142 _PlayListManager
->animate (globalTime
);
1144 animblink (globalTime
);
1146 if (_CurrentSetup
.AnimPlayed
== -1) return;
1147 // take correct 3D animId
1148 uint animID
= _CurrentSetup
.AnimPlayed
;
1149 bool applyRaceScalePos
= true;
1153 if (_CurrentSetup
.Male
&& animID
< _AnimMale
.size())
1155 applyRaceScalePos
= _AnimMale
[animID
].ApplyRaceScalePos
;
1156 // animId is now the correct 3D animId
1157 animID
= _AnimMale
[animID
].AnimId
;
1159 else if (!_CurrentSetup
.Male
&& animID
< _AnimFemale
.size())
1161 applyRaceScalePos
= _AnimFemale
[animID
].ApplyRaceScalePos
;
1162 // animId is now the correct 3D animId
1163 animID
= _AnimFemale
[animID
].AnimId
;
1169 // get the animation
1170 if(animID
==UAnimationSet::NotFound
)
1172 UAnimation
*pAnim
= _AnimationSet
->getAnimation (animID
);
1173 if (pAnim
== NULL
) return;
1174 UTrack
*pTrack
= pAnim
->getTrackByName("pos");
1176 if (pTrack
== NULL
) return;
1178 // Compute animation time (wrapped)
1179 double wrappedTime
=(globalTime
-_PlayList
->getTimeOrigin(0))*_PlayList
->getSpeedFactor(0);
1180 // Mod repeat the time
1182 float length
=pAnim
->getEndTime ()-pAnim
->getBeginTime();
1184 wrappedTime
=pAnim
->getBeginTime()+(float)fmod ((float)wrappedTime
, length
);
1186 wrappedTime
=pAnim
->getBeginTime()+(float)fmod ((float)wrappedTime
, length
)+length
;
1188 pTrack
->interpolate((float)wrappedTime
, animPos
);
1190 // apply race scale pos only if animation need it
1191 if(applyRaceScalePos
)
1192 animPos
*= getGenderInfo(_CurrentSetup
.People
, _CurrentSetup
.Male
)->CharacterScalePos
;
1193 // always apply custom scale pos
1194 animPos
*= _CustomScalePos
;
1195 _PelvisPos
= animPos
;
1196 // update skeleton pelvis pos
1197 if (!_Skeleton
.empty())
1199 _Skeleton
.setPos(_PelvisPos
);
1200 // update skeleton spawn script pos
1201 _Skeleton
.setSSSWOPos(_Root
.getMatrix().getPos());
1202 _Skeleton
.setSSSWODir(_Root
.getMatrix().getJ());
1206 // ------------------------------------------------------------------------------------------------
1207 void CCharacter3D::setPos (float x
, float y
, float z
)
1213 _Root
.setPos (x
, y
, z
);
1216 // ------------------------------------------------------------------------------------------------
1217 void CCharacter3D::setClusterSystem (NL3D::UInstanceGroup
*pIG
)
1219 _ClusterSystem
= pIG
;
1220 if (!_Skeleton
.empty())
1221 _Skeleton
.setClusterSystem(pIG
);
1224 // ------------------------------------------------------------------------------------------------
1225 void CCharacter3D::setRotEuler (float rx
, float ry
, float rz
)
1232 _Root
.setTransformMode (UTransformable::RotEuler
);
1233 _Root
.setRotEuler (_CurRotX
, _CurRotY
, _CurRotZ
);
1237 // ------------------------------------------------------------------------------------------------
1238 void CCharacter3D::getHeadPos (float &x
, float &y
, float &z
)
1241 if (!_Skeleton
.empty())
1243 sint boneId
= _Skeleton
.getBoneIdByName("Bip01 Head");
1246 nlwarning ("bad bone name");
1249 _Skeleton
.forceComputeBone(boneId
);
1250 UBone rBone
= _Skeleton
.getBone(boneId
);
1251 const CMatrix
&rM
= rBone
.getLastWorldMatrixComputed();
1260 nlwarning ("no skeleton");
1264 // ------------------------------------------------------------------------------------------------
1265 void CCharacter3D::setSkeleton (const string
&filename
)
1267 // Remove the old skeleton.
1268 if (!_Skeleton
.empty())
1270 // Must remove first any channels of _Skeleton registered into _PlayList
1272 _PlayList
->resetAllChannels();
1273 _Scene
->deleteSkeleton(_Skeleton
);
1278 _Scene
->deleteTransform(_Root
);
1279 _Root
= _Scene
->createTransform();
1280 // Create the skeleton.
1281 _Skeleton
= _Scene
->createSkeleton(filename
);
1282 if (_Skeleton
.empty())
1284 nlwarning ("CCharacter3D::setSkeleton : Skeleton %s can't be created.", filename
.c_str());
1288 _Skeleton
.setPos (_PelvisPos
);
1289 _Skeleton
.changeMRMDistanceSetup (100.0f
, 150.0f
, 200.0f
);
1290 _Skeleton
.parent(_Root
);
1293 // ------------------------------------------------------------------------------------------------
1294 void CCharacter3D::createInstance (TChar3DPart i
, const SCharacter3DSetup::SCharacterPart
&part
)
1298 nlwarning ("CCharacter3D::createInstance : no scene setup.");
1302 if (!_Instances
[i
].empty())
1303 _Scene
->deleteInstance (_Instances
[i
]);
1305 if ((!part
.Name
.empty()) && (part
.Name
!= "none.shape"))
1306 _Instances
[i
] = _Scene
->createInstance (part
.Name
);
1308 // if cannot create output some errors
1309 if (_Instances
[i
].empty())
1311 if ((i
!= Char3DPart_HandRightItem
) && (i
!= Char3DPart_HandLeftItem
))
1312 nlwarning ("CCharacter3D::createInstance : cannot create the instance : %s.", part
.Name
.c_str());
1319 if (!_InstancesFx
[i
].AdvantageFx
.empty())
1320 _Scene
->deleteInstance (_InstancesFx
[i
].AdvantageFx
);
1322 if ((!part
.AdvFx
.empty()) && (part
.AdvFx
!= "none.shape"))
1324 _InstancesFx
[i
].AdvantageFx
= _Scene
->createInstance (part
.AdvFx
);
1325 if (_InstancesFx
[i
].AdvantageFx
.empty())
1327 nlwarning ("CCharacter3D::createInstance : cannot create the fx : %s.", part
.AdvFx
.c_str());
1331 CMatrix mat
= _Instances
[i
].getMatrix();
1333 mat
*= _InstancesFx
[i
].AdvantageFx
.getMatrix();
1334 _InstancesFx
[i
].AdvantageFx
.setTransformMode(UTransformable::DirectMatrix
);
1335 _InstancesFx
[i
].AdvantageFx
.setMatrix(mat
);
1336 _InstancesFx
[i
].AdvantageFx
.parent(_Instances
[i
]);
1342 for (fx
= 0; fx
< _InstancesFx
[i
].StaticFx
.size(); ++fx
)
1343 if (!_InstancesFx
[i
].StaticFx
[fx
].empty())
1344 _Scene
->deleteInstance(_InstancesFx
[i
].StaticFx
[fx
]);
1345 _InstancesFx
[i
].StaticFx
.clear();
1347 for (fx
= 0; fx
< part
.StatFxNames
.size(); ++fx
)
1348 if ((!part
.StatFxNames
[fx
].empty()) && (part
.StatFxNames
[fx
] != "none.shape") &&
1349 (!part
.StatFxBones
[fx
].empty()) && (part
.StatFxBones
[fx
] != "none.shape"))
1351 sint boneID
= _Skeleton
.getBoneIdByName(part
.StatFxBones
[fx
]);
1354 UInstance instance
= _Scene
->createInstance(part
.StatFxNames
[fx
]);
1355 if (!instance
.empty())
1357 instance
.setTransformMode(UTransform::DirectMatrix
);
1359 mat
.setPos(part
.StatFxOffss
[fx
]);
1360 instance
.setMatrix(mat
);
1361 _Skeleton
.stickObject(instance
, boneID
);
1362 _InstancesFx
[i
].StaticFx
.push_back(instance
);
1366 nlwarning("Can't create static fx %s sticked on bone %s", part
.StatFxNames
[fx
].c_str(), part
.StatFxBones
[fx
].c_str());
1371 nlwarning("Can't find bone %s for static fx %s", part
.StatFxBones
[fx
].c_str(), part
.StatFxNames
[fx
].c_str());
1376 // ------------------------------------------------------------------------------------------------
1377 void CCharacter3D::bindToSkeleton (TChar3DPart i
)
1379 if (_Skeleton
.empty())
1381 nlwarning ("CCharacter3D::bindToSkeleton : no skeleton setup");
1385 if (_Instances
[i
].empty())
1387 if ((i
!= Char3DPart_HandRightItem
) && (i
!= Char3DPart_HandLeftItem
))
1388 nlinfo ("CCharacter3D::bindToSkeleton : no character part for %d", i
);
1394 case Char3DPart_HandRightItem
:
1396 sint rightHandBoneID
= _Skeleton
.getBoneIdByName ("box_arme");
1397 if (rightHandBoneID
!= -1)
1398 _Skeleton
.stickObject (_Instances
[i
], rightHandBoneID
);
1402 case Char3DPart_HandLeftItem
:
1404 sint leftHandBoneID
;
1405 // If this is a shield.
1406 if (_CurrentSetup
.LeftHandItemIsShield
)
1407 leftHandBoneID
= _Skeleton
.getBoneIdByName ("Box_bouclier");
1409 leftHandBoneID
= _Skeleton
.getBoneIdByName ("box_arme_gauche");
1410 if (leftHandBoneID
!= -1)
1411 _Skeleton
.stickObject (_Instances
[i
], leftHandBoneID
);
1416 if (!_Skeleton
.bindSkin(_Instances
[i
]))
1418 nlwarning ("CCharacter3D::bindToSkeleton: Cannot bind the instance : %d.", i
);
1425 // ------------------------------------------------------------------------------------------------
1426 uint32
CCharacter3D::peopleToSkin (EGSPD::CPeople::TPeople people
) const
1430 case EGSPD::CPeople::Matis
:
1433 case EGSPD::CPeople::Tryker
:
1436 case EGSPD::CPeople::Zorai
:
1439 case EGSPD::CPeople::Fyros
:
1445 // ------------------------------------------------------------------------------------------------
1446 void CCharacter3D::animblink (double globalTime
)
1451 static const double blinkTime
= 0.1f
;
1452 static const double minBlinkLength
= 0.5f
;
1453 static const double maxBlinkLength
= 5.0f
;
1455 // Next blink time is valid ?
1456 bool validTime
= (_NextBlinkTime
+ blinkTime
>= globalTime
) && (_NextBlinkTime
<= (globalTime
+ maxBlinkLength
));
1459 bool blinkEnd
= (globalTime
>= _NextBlinkTime
+ blinkTime
);
1461 // Blink is finished or next blink time is invalid ?
1462 if ( blinkEnd
|| !validTime
)
1466 // Compute next time
1467 _NextBlinkTime
= (((double)rand () / (double)RAND_MAX
) * (maxBlinkLength
- minBlinkLength
) + minBlinkLength
+ (double)globalTime
);
1472 if (globalTime
>= _NextBlinkTime
)
1483 // Set the blend shape
1484 if(!_Instances
[Char3DPart_Face
].empty())
1485 _Instances
[Char3DPart_Face
].setBlendShapeFactor ("visage_100", blend
, true);
1488 // ------------------------------------------------------------------------------------------------
1489 CVector
CCharacter3D::getBonePos (const string
&boneName
)
1491 CVector ret
=CVector(0,0,0);
1492 sint boneId
= _Skeleton
.getBoneIdByName(boneName
);
1493 if (boneId
== -1) return ret
;
1494 _Skeleton
.forceComputeBone(boneId
);
1495 UBone rBone
= _Skeleton
.getBone(boneId
);
1496 const CMatrix
&rM
= rBone
.getLastWorldMatrixComputed();
1501 // ------------------------------------------------------------------------------------------------