// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // ------------------------------------------------------------------------------------------------ #include "stdpch.h" #include "character_3d.h" #include "interface_manager.h" #include "../color_slot_manager.h" #include "../sheet_manager.h" #include "../gabarit.h" #include "../misc.h" #include "../time_client.h" #include "../player_cl.h" #include "../player_r2_cl.h" #include "../entities.h" #include "../r2/editor.h" #include "../client_cfg.h" // ------------------------------------------------------------------------------------------------ using namespace std; using namespace NLMISC; using namespace NL3D; using namespace R2; extern CEntityAnimationManager *EAM; // ------------------------------------------------------------------------------------------------ // SCharacter3DSetup // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ SCharacter3DSetup::SCharacter3DSetup () { // Setup a naked male fyros LeftHandItemIsShield = false; People = EGSPD::CPeople::Fyros; Male = true; Skeleton = "fy_hom_skel.skel"; AnimPlayed = 0; Parts[Char3DPart_Chest].Name = "FY_HOM_underwear_gilet.shape"; Parts[Char3DPart_Legs].Name = "FY_HOM_underwear_pantabottes.shape"; Parts[Char3DPart_Arms].Name = "FY_HOM_underwear_armpad.shape"; Parts[Char3DPart_Feet].Name = "FY_HOM_underwear_bottes.shape"; Parts[Char3DPart_Face].Name = "FY_HOM_visage.shape"; Parts[Char3DPart_Head].Name = "FY_HOM_cheveux_medium01.shape"; Parts[Char3DPart_Hands].Name = "TR_HOM_underwear_hand.shape"; Parts[Char3DPart_HandRightItem].Name = ""; Parts[Char3DPart_HandLeftItem].Name = ""; for (uint32 i = 0; i < NB_CHARACTER3D_PARTS; ++i) { Parts[i].Color = 0; Parts[i].Quality = -1; } Tattoo = 0; EyesColor = 0; HairColor = 0; CharHeight = 0.0f; ChestWidth = 0.0f; ArmsWidth = 0.0f; LegsWidth = 0.0f; BreastSize = 0.0f; HideFace = false; for (uint32 i = 0; i < NB_MORPH_TARGETS; ++i) MorphTarget[i] = 0.0f; } // ------------------------------------------------------------------------------------------------ static CGenderInfo *getGenderInfo (EGSPD::CPeople::TPeople ePeople, bool bMale) { // Read in the race_stats forms the default equipement CSheetId RSid; switch (ePeople) { case EGSPD::CPeople::Tryker: RSid = CSheetId("tryker.race_stats"); break; case EGSPD::CPeople::Matis: RSid = CSheetId("matis.race_stats"); break; case EGSPD::CPeople::Zorai: RSid = CSheetId("zorai.race_stats"); break; case EGSPD::CPeople::Fyros: default: RSid = CSheetId("fyros.race_stats"); break; } CRaceStatsSheet *pRSS = dynamic_cast(SheetMngr.get (RSid)); if (pRSS == NULL) { nlwarning ("cannot find sheet for people:%d male:%d", ePeople, bMale); return NULL; } // Choose default stuff is we are male or female CGenderInfo *pGI; if (bMale) pGI = &pRSS->GenderInfos[0]; else pGI = &pRSS->GenderInfos[1]; return pGI; } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupDefault (EGSPD::CPeople::TPeople eRace, bool bMale) { People = eRace; Male = bMale; CGenderInfo *pGI = getGenderInfo(eRace, bMale); if (pGI == NULL) return; Skeleton = pGI->Skelfilename; // Read all the default equipement for (sint32 i = 0; i < SLOTTYPE::NB_SLOT; ++i) { string ISstr = pGI->Items[i]; // All the strings are items if (!ISstr.empty()) { CItemSheet *pIS = dynamic_cast(SheetMngr.get(CSheetId(ISstr))); if (pIS != NULL) { sint32 cpIndex = convert_VisualSlot_To_Char3DPart ((SLOTTYPE::EVisualSlot)i); if (cpIndex != Char3DPart_INVALID) { Parts[i].Quality = pIS->MapVariant; if (Male) Parts[cpIndex].Name = pIS->getShape(); else Parts[cpIndex].Name = pIS->getShapeFemale(); } } } } } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupFromCharacterSummary (const CCharacterSummary &cs) { const SPropVisualA::SPropSubData &rPVA = cs.VisualPropA.PropertySubData; const SPropVisualB::SPropSubData &rPVB = cs.VisualPropB.PropertySubData; const SPropVisualC::SPropSubData &rPVC = cs.VisualPropC.PropertySubData; setupDefault (cs.People, (rPVA.Sex == 0)); // Setup char3dParts with additionnal info setupFromCS_ModelCol (SLOTTYPE::CHEST_SLOT, rPVA.JacketModel, rPVA.JacketColor); setupFromCS_ModelCol (SLOTTYPE::LEGS_SLOT, rPVA.TrouserModel, rPVA.TrouserColor); setupFromCS_ModelCol (SLOTTYPE::HEAD_SLOT, rPVA.HatModel, rPVA.HatColor); // Should have to hide the face ? { // TChar3DPart part = convert_VisualSlot_To_Char3DPart (SLOTTYPE::HEAD_SLOT); CItemSheet *item = SheetMngr.getItem (SLOTTYPE::HEAD_SLOT, rPVA.HatModel); if ((item != NULL) && ((item->Family == ITEMFAMILY::ARMOR) || (item->Family == ITEMFAMILY::SHIELD))) HideFace = true; else HideFace = false; } setupFromCS_ModelCol (SLOTTYPE::ARMS_SLOT, rPVA.ArmModel, rPVA.ArmColor); // setupFromCS_Model (SLOTTYPE::FACE_SLOT, ?????????????); setupFromCS_ModelCol (SLOTTYPE::FEET_SLOT, rPVB.FeetModel, rPVB.FeetColor); setupFromCS_ModelCol (SLOTTYPE::RIGHT_HAND_SLOT, rPVA.WeaponRightHand, 0); setupFromCS_ModelCol (SLOTTYPE::LEFT_HAND_SLOT, rPVA.WeaponLeftHand, 0); // armor gloves are not displayed if character has the 'weapon' magician gloves { CItemSheet *item = SheetMngr.getItem (SLOTTYPE::RIGHT_HAND_SLOT, rPVA.WeaponRightHand); if( ! ((item != NULL)&&(item->ItemType == ITEM_TYPE::MAGICIAN_STAFF) ) ) setupFromCS_ModelCol (SLOTTYPE::HANDS_SLOT, rPVB.HandsModel, rPVB.HandsColor); } Tattoo = rPVC.Tattoo; HairColor = rPVA.HatColor; // TODO : For the moment no diff between hair color and head color !!! EyesColor = rPVC.EyesColor; CharHeight = (rPVC.CharacterHeight - 7.0f) / 7.0f; ChestWidth = (rPVC.TorsoWidth - 7.0f) / 7.0f; ArmsWidth = (rPVC.ArmsWidth - 7.0f) / 7.0f; LegsWidth = (rPVC.LegsWidth - 7.0f) / 7.0f; BreastSize = (rPVC.BreastSize - 7.0f) / 7.0f; float MTmin, MTmax; CGenderInfo *pGI = getGenderInfo (cs.People, (rPVA.Sex == 0)); if (pGI == NULL) return; MTmin = pGI->BlendShapeMin[0]; MTmax = pGI->BlendShapeMax[0]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[0] = rPVC.MorphTarget1 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[1]; MTmax = pGI->BlendShapeMax[1]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[1] = rPVC.MorphTarget2 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[2]; MTmax = pGI->BlendShapeMax[2]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[2] = rPVC.MorphTarget3 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[3]; MTmax = pGI->BlendShapeMax[3]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[3] = rPVC.MorphTarget4 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[4]; MTmax = pGI->BlendShapeMax[4]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[4] = rPVC.MorphTarget5 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[5]; MTmax = pGI->BlendShapeMax[5]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[5] = rPVC.MorphTarget6 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[6]; MTmax = pGI->BlendShapeMax[6]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[6] = rPVC.MorphTarget7 / 7.0f * (MTmax - MTmin) + MTmin; MTmin = pGI->BlendShapeMin[7]; MTmax = pGI->BlendShapeMax[7]; if (!ClientCfg.BlendShapePatched) { MTmin = 0.0f; MTmax = 100.0f; } MorphTarget[7] = rPVC.MorphTarget8 / 7.0f * (MTmax - MTmin) + MTmin; } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupFromDataBase (const std::string &branchName) { CCharacterSummary CS; setupCharacterSummaryFromDB(CS, branchName); setupFromCharacterSummary (CS); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupFromSERVERDataBase (uint8 nEntity) { CCharacterSummary CS; setupCharacterSummaryFromSERVERDB(CS, nEntity); setupFromCharacterSummary (CS); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupDBFromCharacterSummary (const string &branchName, const CCharacterSummary &CS) { setDB (branchName+":PEOPLE", CS.People); setDB (branchName+":VPA:SEX", CS.VisualPropA.PropertySubData.Sex); setDB (branchName+":VPA:JACKETMODEL", CS.VisualPropA.PropertySubData.JacketModel); setDB (branchName+":VPA:JACKETCOLOR", CS.VisualPropA.PropertySubData.JacketColor); setDB (branchName+":VPA:TROUSERMODEL", CS.VisualPropA.PropertySubData.TrouserModel); setDB (branchName+":VPA:TROUSERCOLOR", CS.VisualPropA.PropertySubData.TrouserColor); setDB (branchName+":VPA:WEAPONRIGHTHAND", CS.VisualPropA.PropertySubData.WeaponRightHand); setDB (branchName+":VPA:WEAPONLEFTHAND", CS.VisualPropA.PropertySubData.WeaponLeftHand); setDB (branchName+":VPA:ARMMODEL", CS.VisualPropA.PropertySubData.ArmModel); setDB (branchName+":VPA:ARMCOLOR", CS.VisualPropA.PropertySubData.ArmColor); setDB (branchName+":VPA:HATMODEL", CS.VisualPropA.PropertySubData.HatModel); setDB (branchName+":VPA:HATCOLOR", CS.VisualPropA.PropertySubData.HatColor); setDB (branchName+":VPB:NAME", CS.VisualPropB.PropertySubData.Name); setDB (branchName+":VPB:HANDSMODEL", CS.VisualPropB.PropertySubData.HandsModel); setDB (branchName+":VPB:HANDSCOLOR", CS.VisualPropB.PropertySubData.HandsColor); setDB (branchName+":VPB:FEETMODEL", CS.VisualPropB.PropertySubData.FeetModel); setDB (branchName+":VPB:FEETCOLOR", CS.VisualPropB.PropertySubData.FeetColor); setDB (branchName+":VPC:MORPHTARGET1", CS.VisualPropC.PropertySubData.MorphTarget1); setDB (branchName+":VPC:MORPHTARGET2", CS.VisualPropC.PropertySubData.MorphTarget2); setDB (branchName+":VPC:MORPHTARGET3", CS.VisualPropC.PropertySubData.MorphTarget3); setDB (branchName+":VPC:MORPHTARGET4", CS.VisualPropC.PropertySubData.MorphTarget4); setDB (branchName+":VPC:MORPHTARGET5", CS.VisualPropC.PropertySubData.MorphTarget5); setDB (branchName+":VPC:MORPHTARGET6", CS.VisualPropC.PropertySubData.MorphTarget6); setDB (branchName+":VPC:MORPHTARGET7", CS.VisualPropC.PropertySubData.MorphTarget7); setDB (branchName+":VPC:MORPHTARGET8", CS.VisualPropC.PropertySubData.MorphTarget8); setDB (branchName+":VPC:EYESCOLOR", CS.VisualPropC.PropertySubData.EyesColor); setDB (branchName+":VPC:TATTOO", CS.VisualPropC.PropertySubData.Tattoo); setDB (branchName+":VPC:CHARACTERHEIGHT", CS.VisualPropC.PropertySubData.CharacterHeight); setDB (branchName+":VPC:TORSOWIDTH", CS.VisualPropC.PropertySubData.TorsoWidth); setDB (branchName+":VPC:ARMSWIDTH", CS.VisualPropC.PropertySubData.ArmsWidth); setDB (branchName+":VPC:LEGSWIDTH", CS.VisualPropC.PropertySubData.LegsWidth); setDB (branchName+":VPC:BREASTSIZE", CS.VisualPropC.PropertySubData.BreastSize); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupCharacterSummaryFromDB (CCharacterSummary &CS, const string &branchName) { CS.People = (EGSPD::CPeople::TPeople)getDB (branchName+":PEOPLE"); CS.VisualPropA.PropertySubData.Sex = getDB (branchName+":VPA:SEX"); CS.VisualPropA.PropertySubData.JacketModel = getDB (branchName+":VPA:JACKETMODEL"); CS.VisualPropA.PropertySubData.JacketColor = getDB (branchName+":VPA:JACKETCOLOR"); CS.VisualPropA.PropertySubData.TrouserModel = getDB (branchName+":VPA:TROUSERMODEL"); CS.VisualPropA.PropertySubData.TrouserColor = getDB (branchName+":VPA:TROUSERCOLOR"); CS.VisualPropA.PropertySubData.WeaponRightHand = getDB (branchName+":VPA:WEAPONRIGHTHAND"); CS.VisualPropA.PropertySubData.WeaponLeftHand = getDB (branchName+":VPA:WEAPONLEFTHAND"); CS.VisualPropA.PropertySubData.ArmModel = getDB (branchName+":VPA:ARMMODEL"); CS.VisualPropA.PropertySubData.ArmColor = getDB (branchName+":VPA:ARMCOLOR"); CS.VisualPropA.PropertySubData.HatModel = getDB (branchName+":VPA:HATMODEL"); CS.VisualPropA.PropertySubData.HatColor = getDB (branchName+":VPA:HATCOLOR"); CS.VisualPropB.PropertySubData.Name = getDB (branchName+":VPB:NAME"); CS.VisualPropB.PropertySubData.HandsModel = getDB (branchName+":VPB:HANDSMODEL"); CS.VisualPropB.PropertySubData.HandsColor = getDB (branchName+":VPB:HANDSCOLOR"); CS.VisualPropB.PropertySubData.FeetModel = getDB (branchName+":VPB:FEETMODEL"); CS.VisualPropB.PropertySubData.FeetColor = getDB (branchName+":VPB:FEETCOLOR"); CS.VisualPropC.PropertySubData.MorphTarget1 = getDB (branchName+":VPC:MORPHTARGET1"); CS.VisualPropC.PropertySubData.MorphTarget2 = getDB (branchName+":VPC:MORPHTARGET2"); CS.VisualPropC.PropertySubData.MorphTarget3 = getDB (branchName+":VPC:MORPHTARGET3"); CS.VisualPropC.PropertySubData.MorphTarget4 = getDB (branchName+":VPC:MORPHTARGET4"); CS.VisualPropC.PropertySubData.MorphTarget5 = getDB (branchName+":VPC:MORPHTARGET5"); CS.VisualPropC.PropertySubData.MorphTarget6 = getDB (branchName+":VPC:MORPHTARGET6"); CS.VisualPropC.PropertySubData.MorphTarget7 = getDB (branchName+":VPC:MORPHTARGET7"); CS.VisualPropC.PropertySubData.MorphTarget8 = getDB (branchName+":VPC:MORPHTARGET8"); CS.VisualPropC.PropertySubData.EyesColor = getDB (branchName+":VPC:EYESCOLOR"); CS.VisualPropC.PropertySubData.Tattoo = getDB (branchName+":VPC:TATTOO"); CS.VisualPropC.PropertySubData.CharacterHeight = getDB (branchName+":VPC:CHARACTERHEIGHT"); CS.VisualPropC.PropertySubData.TorsoWidth = getDB (branchName+":VPC:TORSOWIDTH"); CS.VisualPropC.PropertySubData.ArmsWidth = getDB (branchName+":VPC:ARMSWIDTH"); CS.VisualPropC.PropertySubData.LegsWidth = getDB (branchName+":VPC:LEGSWIDTH"); CS.VisualPropC.PropertySubData.BreastSize = getDB (branchName+":VPC:BREASTSIZE"); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupCharacterSummaryFromSERVERDB (CCharacterSummary &cs, uint8 entityID) { cs.VisualPropA = getDB ("SERVER:Entities:E"+NLMISC::toString(entityID)+ ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPA)); cs.VisualPropB = getDB ("SERVER:Entities:E"+NLMISC::toString(entityID)+ ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPB)); cs.VisualPropC = getDB ("SERVER:Entities:E"+NLMISC::toString(entityID)+ ":P"+NLMISC::toString(CLFECOMMON::PROPERTY_VPC)); cs.People = EGSPD::CPeople::Fyros; CPlayerCL *pp = NULL; if ((pp=dynamic_cast(EntitiesMngr.entity(entityID))) == NULL) { pp=(CPlayerCL*)dynamic_cast(EntitiesMngr.entity(entityID)); } if(pp) { cs.People = pp->people(); cs.VisualPropA.PropertySubData.Sex = (pp->getGender() == GSGENDER::female); } } // ------------------------------------------------------------------------------------------------ TChar3DPart SCharacter3DSetup::convert_VisualSlot_To_Char3DPart (SLOTTYPE::EVisualSlot vs) { switch (vs) { case SLOTTYPE::HIDDEN_SLOT: return Char3DPart_INVALID; case SLOTTYPE::CHEST_SLOT: return Char3DPart_Chest; case SLOTTYPE::LEGS_SLOT: return Char3DPart_Legs; case SLOTTYPE::HEAD_SLOT: return Char3DPart_Head; case SLOTTYPE::ARMS_SLOT: return Char3DPart_Arms; case SLOTTYPE::FACE_SLOT: return Char3DPart_Face; case SLOTTYPE::HANDS_SLOT: return Char3DPart_Hands; case SLOTTYPE::FEET_SLOT: return Char3DPart_Feet; case SLOTTYPE::RIGHT_HAND_SLOT: return Char3DPart_HandRightItem; case SLOTTYPE::LEFT_HAND_SLOT: return Char3DPart_HandLeftItem; case SLOTTYPE::NB_SLOT: return Char3DPart_INVALID; default: break; } return Char3DPart_INVALID; } // ------------------------------------------------------------------------------------------------ SLOTTYPE::EVisualSlot SCharacter3DSetup::convert_Char3DPart_To_VisualSlot (TChar3DPart cp) { switch (cp) { case Char3DPart_Chest: return SLOTTYPE::CHEST_SLOT; case Char3DPart_Legs: return SLOTTYPE::LEGS_SLOT; case Char3DPart_Head: return SLOTTYPE::HEAD_SLOT; case Char3DPart_Arms: return SLOTTYPE::ARMS_SLOT; case Char3DPart_Face: return SLOTTYPE::FACE_SLOT; case Char3DPart_Hands: return SLOTTYPE::HANDS_SLOT; case Char3DPart_Feet: return SLOTTYPE::FEET_SLOT; case Char3DPart_HandRightItem: return SLOTTYPE::RIGHT_HAND_SLOT; case Char3DPart_HandLeftItem: return SLOTTYPE::LEFT_HAND_SLOT; case Char3DPart_INVALID: return SLOTTYPE::NB_SLOT; default: break; } return SLOTTYPE::HIDDEN_SLOT; } // ------------------------------------------------------------------------------------------------ string SCharacter3DSetup::convert_VisualSlot_To_String (SLOTTYPE::EVisualSlot vs) { switch (vs) { case SLOTTYPE::HIDDEN_SLOT: return string("Hidden"); case SLOTTYPE::CHEST_SLOT: return string("Chest"); case SLOTTYPE::LEGS_SLOT: return string("Legs"); case SLOTTYPE::HEAD_SLOT: return string("Head"); case SLOTTYPE::ARMS_SLOT: return string("Arms"); case SLOTTYPE::FACE_SLOT: return string("Face"); case SLOTTYPE::HANDS_SLOT: return string("Hands"); case SLOTTYPE::FEET_SLOT: return string("Feet"); case SLOTTYPE::RIGHT_HAND_SLOT: return string("Hand Right Item"); case SLOTTYPE::LEFT_HAND_SLOT: return string("Hand Left Item"); case SLOTTYPE::NB_SLOT: return string("Number Of Slot"); default: break; } return string("Invalid"); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setupFromCS_ModelCol (SLOTTYPE::EVisualSlot s, sint32 model, sint32 col) { TChar3DPart part = convert_VisualSlot_To_Char3DPart (s); if (part == Char3DPart_INVALID) return; CItemSheet *item = SheetMngr.getItem (s, model); if (item != NULL) { // magician gloves are a weapon but displayed in hands slot(armor gloves) if( (s == SLOTTYPE::RIGHT_HAND_SLOT) && (item->ItemType == ITEM_TYPE::MAGICIAN_STAFF) ) { Parts[part].Name = "none.shape"; part = convert_VisualSlot_To_Char3DPart (SLOTTYPE::HANDS_SLOT); } Parts[part].Quality = item->MapVariant; if (Male) Parts[part].Name = item->getShape(); else Parts[part].Name = item->getShapeFemale(); // FX { Parts[part].AdvFx = item->FX.getAdvantageFX(); Parts[part].StatFxNames.clear(); Parts[part].StatFxBones.clear(); Parts[part].StatFxOffss.clear(); for (uint32 fx = 0; fx < item->FX.getNumStaticFX(); ++fx) { Parts[part].StatFxNames.push_back(item->FX.getStaticFXName(fx)); Parts[part].StatFxBones.push_back(item->FX.getStaticFXBone(fx)); Parts[part].StatFxOffss.push_back(item->FX.getStaticFXOffset(fx)); } } if (part == Char3DPart_HandLeftItem) { if ((item->ItemType == ITEM_TYPE::SHIELD) || (item->ItemType == ITEM_TYPE::BUCKLER)) LeftHandItemIsShield = true; else LeftHandItemIsShield = false; } } else { if ((part == Char3DPart_HandLeftItem) || (part == Char3DPart_HandRightItem)) Parts[part].Name = "none.shape"; } Parts[part].Color = col; } // ------------------------------------------------------------------------------------------------ uint64 SCharacter3DSetup::getDB (const string &name) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CCDBNodeLeaf *pNL = pIM->getDbProp(name); if (pNL == NULL) return 0; return pNL->getValue64(); } // ------------------------------------------------------------------------------------------------ void SCharacter3DSetup::setDB (const string &name, uint64 val) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CCDBNodeLeaf *pNL = pIM->getDbProp(name); if (pNL == NULL) return; pNL->setValue64(val); } // ------------------------------------------------------------------------------------------------ void DEBUG_DumpClothes() { for (uint cp = 0; cp < NB_CHARACTER3D_PARTS; ++cp) if (cp != Char3DPart_Face) { SLOTTYPE::EVisualSlot vs = SCharacter3DSetup::convert_Char3DPart_To_VisualSlot((TChar3DPart)cp); string sTmp = SCharacter3DSetup::convert_VisualSlot_To_String(vs); nlinfo("*** PART *** : %s", sTmp.c_str()); uint nNbItems; if (cp == Char3DPart_HandRightItem) nNbItems = 1<<11; if ((cp == Char3DPart_Chest) || (cp == Char3DPart_Hands) || (cp == Char3DPart_Feet)) nNbItems = 1<<9; if ((cp == Char3DPart_Legs) || (cp == Char3DPart_Arms) || (cp == Char3DPart_HandLeftItem)) nNbItems = 1<<8; if (cp == Char3DPart_Head) nNbItems = 1<<7; for (uint it = 0; it < nNbItems; ++it) { CItemSheet *item = SheetMngr.getItem (vs, it); if (item == NULL) { //nlinfo(" val:%d UNKNOWN",it); } else { //nlinfo(" val:%d M[%s] F[%s]", it, item->Shape.c_str(), item->ShapeFemale.c_str()); const CSheetManager::TEntitySheetMap &esm = SheetMngr.getSheets(); CSheetManager::TEntitySheetMap::const_iterator esmit = esm.begin(); while (esmit != esm.end()) { if (esmit->second.EntitySheet == item) { nlinfo(" val:%d item[%s]", it, esmit->first.toString().c_str() ); break; } esmit++; } } nlSleep(1); } } } // ------------------------------------------------------------------------------------------------ // CCharacter3D // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ CCharacter3D::CCharacter3D() { _ClusterSystem = NULL; _Scene = NULL; _PlayListManager = NULL; _AnimationSet = NULL; _PlayList = NULL; _FacePlayList = NULL; // Clear the cache to make it work with 1st init _CurrentSetup.Skeleton = ""; _CurrentSetup.AnimPlayed = -1; for (uint32 i = 0; i < NB_CHARACTER3D_PARTS; ++i) { _CurrentSetup.Parts[i].Name = ""; _CurrentSetup.Parts[i].Color = -1; _CurrentSetup.Parts[i].Quality = -1; } _CurrentSetup.Tattoo = -1; _CurrentSetup.EyesColor = -1; _CurrentSetup.CharHeight = _CurrentSetup.ChestWidth = -20.0f; _CurrentSetup.ArmsWidth = _CurrentSetup.LegsWidth = _CurrentSetup.BreastSize = -20.0f; _PelvisPos.set(0.f,0.f,-20.0f); _CurPosX = _CurPosY = _CurPosZ = 0.0f; _CurRotX, _CurRotY, _CurRotZ = 0.0f; _NextBlinkTime = 0; _CopyAnim=false; } // ------------------------------------------------------------------------------------------------ CCharacter3D::~CCharacter3D() { if (_Scene == NULL) return; // Delete animations first if (_PlayListManager != NULL) { if (_PlayList != NULL) { _PlayList->resetAllChannels(); _PlayListManager->deletePlayList(_PlayList); } if (_FacePlayList != NULL) { _FacePlayList->resetAllChannels(); _PlayListManager->deletePlayList(_FacePlayList); } _Scene->deletePlayListManager(_PlayListManager); } _AnimationSet= NULL; // delete instances for (uint32 i = 0; i < NB_CHARACTER3D_PARTS; ++i) { if (!_Instances[i].empty()) _Scene->deleteInstance (_Instances[i]); for (uint32 fx = 0; fx < _InstancesFx[i].StaticFx.size(); ++fx) if (!_InstancesFx[i].StaticFx[fx].empty()) _Scene->deleteInstance(_InstancesFx[i].StaticFx[fx]); _InstancesFx[i].StaticFx.clear(); if (!_InstancesFx[i].AdvantageFx.empty()) _Scene->deleteInstance (_InstancesFx[i].AdvantageFx); } // delete skeleton if(!_Skeleton.empty()) _Scene->deleteSkeleton(_Skeleton); _Scene= NULL; } // ------------------------------------------------------------------------------------------------ bool CCharacter3D::init (UScene *pScene) { // DEBUG_DumpClothes(); if (_Scene != NULL) return true; _Scene = pScene; _PlayListManager = _Scene->createPlayListManager(); if (!_PlayListManager) { nlwarning ("CCharacter3D : couldn't create playlist manager"); return false; } // ANIMATIONS CInterfaceManager *pIM = CInterfaceManager::getInstance(); COptionsAnimationSet *pOAS= dynamic_cast(pIM->getOptions("character_animations")); if(!pOAS || !pOAS->AnimationSet) { nlwarning("Not found 'character_animations', or not of type 'animation_set'"); return false; } if(ClientCfg.Light || !ClientCfg.EAMEnabled) _CopyAnim = false; // Retrieve the animation info if(!_CopyAnim) { resetAnimation (pOAS->AnimationSet); _AnimMale= pOAS->AnimMale; _AnimFemale= pOAS->AnimFemale; } else { if (EAM) { resetAnimation (EAM->getAnimationSet()); } } return true; } // ------------------------------------------------------------------------------------------------ void CCharacter3D::resetAnimation (UAnimationSet *animSet) { nlassert(animSet); if (_PlayList) _PlayList->resetAllChannels(); if (_FacePlayList) _FacePlayList->resetAllChannels(); // if (_PlayList != NULL) _PlayListManager->deletePlayList (_PlayList); // if (_FacePlayList != NULL) _PlayListManager->deletePlayList (_FacePlayList); _AnimationSet= animSet; if (_PlayList == NULL) _PlayList = _PlayListManager->createPlayList(_AnimationSet); if (!_PlayList) { nlwarning ("CCharacter3D : couldn't create play list"); _Scene->deletePlayListManager (_PlayListManager); _PlayListManager = NULL; _AnimationSet = NULL; return; } if (_FacePlayList == NULL) _FacePlayList = _PlayListManager->createPlayList (_AnimationSet); if (!_FacePlayList) { nlwarning ("CCharacter3D : couldn't create face play list"); // no face anim, but body anim is still available return; } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::disableFaceMorphAndBlinks() { if(_FacePlayList && _AnimationSet) { // disable eye blink animation (handled by ourselves) sint id= _AnimationSet->getChannelIdByName("visage_100MorphFactor"); if(id!=UAnimationSet::NotFound) _FacePlayList->enableChannel(id, false); // disable morph target (handled by ourselves) for(uint i=0;igetChannelIdByName(baseName + toString(i) + "MorphFactor"); if(id!=UAnimationSet::NotFound) _FacePlayList->enableChannel(id, false); } } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setup (const SCharacter3DSetup &c3ds) { bool bSkeletonRebuilt = false; // Test with cache and call dressing/loading functions if (!c3ds.Skeleton.empty()) if (c3ds.Skeleton != _CurrentSetup.Skeleton) { setSkeleton (c3ds.Skeleton); _CurrentSetup.Skeleton = c3ds.Skeleton; bSkeletonRebuilt = true; _Skeleton.setClusterSystem (_ClusterSystem); if (_PlayList) { _PlayList->registerTransform (_Skeleton); // disable pos animation sint id= _AnimationSet->getChannelIdByName("pos"); if(id!=UAnimationSet::NotFound) _PlayList->enableChannel(id, false); } } // Information that are additionnal _CurrentSetup.LeftHandItemIsShield = c3ds.LeftHandItemIsShield; _CurrentSetup.Male = c3ds.Male; // Setup instances uint32 i; for (i = 0; i < NB_CHARACTER3D_PARTS; ++i) { bool bInstanceRebuilt = false; bool bQualityRebuilt = false; // Create Instance if ((c3ds.Parts[i].Name != _CurrentSetup.Parts[i].Name) || (c3ds.Parts[i].AdvFx != _CurrentSetup.Parts[i].AdvFx)) { // If face, unregister FacePlayList if(i==Char3DPart_Face && _FacePlayList) _FacePlayList->resetAllChannels(); // rebuild this instance bInstanceRebuilt = true; createInstance ((TChar3DPart)i, c3ds.Parts[i]); _CurrentSetup.Parts[i].Name = c3ds.Parts[i].Name; _CurrentSetup.Parts[i].AdvFx = c3ds.Parts[i].AdvFx; _CurrentSetup.Parts[i].StatFxNames = c3ds.Parts[i].StatFxNames; _CurrentSetup.Parts[i].StatFxBones = c3ds.Parts[i].StatFxBones; _CurrentSetup.Parts[i].StatFxOffss = c3ds.Parts[i].StatFxOffss; // If face and instance created, reassign FacePlayList if(i==Char3DPart_Face && _FacePlayList && !_Instances[Char3DPart_Face].empty()) { _FacePlayList->registerTransform(_Instances[Char3DPart_Face]); disableFaceMorphAndBlinks(); } } // Quality if (c3ds.Parts[i].Quality != -1) if ((c3ds.Parts[i].Quality != _CurrentSetup.Parts[i].Quality) || bInstanceRebuilt) { if (!_Instances[i].empty()) { _Instances[i].selectTextureSet((uint)c3ds.Parts[i].Quality); bQualityRebuilt = true; } _CurrentSetup.Parts[i].Quality = c3ds.Parts[i].Quality; } // Instance user color if (c3ds.Parts[i].Color != -1) if ((c3ds.Parts[i].Color != _CurrentSetup.Parts[i].Color) || bInstanceRebuilt || bQualityRebuilt) { if (!_Instances[i].empty()) { ColorSlotManager.setInstanceSlot ( _Instances[i], 1u, // Slot 1 is for user color c3ds.Parts[i].Color); } _CurrentSetup.Parts[i].Color = c3ds.Parts[i].Color; } // Instance skin color if (c3ds.People != -1) if ((c3ds.People != _CurrentSetup.People) || bInstanceRebuilt || bQualityRebuilt) { if (!_Instances[i].empty()) { ColorSlotManager.setInstanceSlot ( _Instances[i], 0u, // Slot 0 is for skin peopleToSkin(c3ds.People)); } // Here we do not update current setup people value to let other instances colorize too } // Special cases switch(i) { case Char3DPart_Face: // Setup tatoo if (c3ds.Tattoo != -1) if ((c3ds.Tattoo != _CurrentSetup.Tattoo) || bInstanceRebuilt) { if (!_Instances[Char3DPart_Face].empty()) makeUp (_Instances[Char3DPart_Face], c3ds.Tattoo); _CurrentSetup.Tattoo = c3ds.Tattoo; } // Setup eyes color if (c3ds.EyesColor != -1) if ((c3ds.EyesColor != _CurrentSetup.EyesColor) ||bInstanceRebuilt) { if (!_Instances[Char3DPart_Face].empty()) ColorSlotManager.setInstanceSlot ( _Instances[Char3DPart_Face], (uint)3, // slot 3 is for eyes colors c3ds.EyesColor ); _CurrentSetup.EyesColor = c3ds.EyesColor; } // Setup morph targets if ((c3ds.MorphTarget[0] != _CurrentSetup.MorphTarget[0]) || (c3ds.MorphTarget[1] != _CurrentSetup.MorphTarget[1]) || (c3ds.MorphTarget[2] != _CurrentSetup.MorphTarget[2]) || (c3ds.MorphTarget[3] != _CurrentSetup.MorphTarget[3]) || (c3ds.MorphTarget[4] != _CurrentSetup.MorphTarget[4]) || (c3ds.MorphTarget[5] != _CurrentSetup.MorphTarget[5]) || (c3ds.MorphTarget[6] != _CurrentSetup.MorphTarget[6]) || (c3ds.MorphTarget[7] != _CurrentSetup.MorphTarget[7]) || bInstanceRebuilt || bSkeletonRebuilt) { if (!_Instances[Char3DPart_Face].empty()) { for(uint k = 0; k < NB_MORPH_TARGETS; ++k) { static const char *baseName = "visage_00"; _Instances[Char3DPart_Face].setBlendShapeFactor (baseName + toString(k), c3ds.MorphTarget[k], true); _CurrentSetup.MorphTarget[k] = c3ds.MorphTarget[k]; } } } if (!_Instances[Char3DPart_Face].empty()) { if (c3ds.HideFace) _Instances[Char3DPart_Face].hide(); else _Instances[Char3DPart_Face].show(); } _CurrentSetup.HideFace = c3ds.HideFace; // Setup hair color (for both part) if (c3ds.HairColor != -1) if ((c3ds.HairColor!= _CurrentSetup.HairColor) || bInstanceRebuilt) { if (!_Instances[Char3DPart_Face].empty()) ColorSlotManager.setInstanceSlot ( _Instances[Char3DPart_Face], (uint)2, // slot 2 is for hair color c3ds.HairColor ); //_CurrentSetup.HairColor = c3ds.HairColor; } break; case Char3DPart_Head: // Setup hair color if (c3ds.HairColor != -1) if ((c3ds.HairColor!= _CurrentSetup.HairColor) || bInstanceRebuilt) { if (!_Instances[Char3DPart_Head].empty()) ColorSlotManager.setInstanceSlot ( _Instances[Char3DPart_Head], (uint)2, // slot 2 is for hair color c3ds.HairColor ); _CurrentSetup.HairColor = c3ds.HairColor; } break; default: break; } // Bind instance to skeleton if (bInstanceRebuilt || bSkeletonRebuilt) { bindToSkeleton ((TChar3DPart)i); } } _CurrentSetup.People = c3ds.People; // Because not done for each instance // Setup gabarit bool bGabaritChanged = false; if ((c3ds.CharHeight != _CurrentSetup.CharHeight) || (c3ds.ChestWidth != _CurrentSetup.ChestWidth) || (c3ds.ArmsWidth != _CurrentSetup.ArmsWidth) || (c3ds.LegsWidth != _CurrentSetup.LegsWidth) || (c3ds.BreastSize != _CurrentSetup.BreastSize) || bSkeletonRebuilt) { uint gender = _CurrentSetup.Male ? 0 : 1; float heightScale; GabaritSet.applyGabarit ( _Skeleton, gender, _CurrentSetup.People, c3ds.CharHeight, c3ds.ChestWidth, c3ds.ArmsWidth, c3ds.LegsWidth, c3ds.BreastSize, &heightScale ); float refHeightScale = GabaritSet.getRefHeightScale(gender, _CurrentSetup.People); // dummy code, to avoid 1 frame big swap _PelvisPos.z = 1.f * heightScale; _CurrentSetup.CharHeight = c3ds.CharHeight; _CurrentSetup.ChestWidth = c3ds.ChestWidth; _CurrentSetup.ArmsWidth = c3ds.ArmsWidth; _CurrentSetup.LegsWidth = c3ds.LegsWidth; _CurrentSetup.BreastSize = c3ds.BreastSize; if(refHeightScale != 0.f) _CustomScalePos = heightScale/refHeightScale; else _CustomScalePos = 1.f; bGabaritChanged = true; } // Play an animation if (c3ds.AnimPlayed != -1) if ((c3ds.AnimPlayed != _CurrentSetup.AnimPlayed) || (bSkeletonRebuilt) || _CopyAnim) setAnim (c3ds.AnimPlayed); if (bSkeletonRebuilt || bGabaritChanged) animate(0.0); // If skeleton or gabarit has changed replace correctly the skeleton from feet reference point setPos (_CurPosX, _CurPosY, _CurPosZ); setRotEuler (_CurRotX, _CurRotY, _CurRotZ); // update skeleton pelvis pos if (!_Skeleton.empty()) _Skeleton.setPos(_PelvisPos); } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setAnim (uint animID) { CCharacterCL * character = NULL; if(!_CopyAnim) { _CurrentSetup.AnimPlayed = animID; if (_CurrentSetup.Male) { if (animID >= _AnimMale.size()) return; animID = _AnimMale[animID].AnimId; } else { if (animID >= _AnimFemale.size()) return; animID = _AnimFemale[animID].AnimId; } } else { CInstance * selectedInst = getEditor().getSelectedInstance(); if(!selectedInst) return; CEntityCL * entity = selectedInst->getEntity(); if(!(entity && ((character=dynamic_cast(entity))!=NULL))) return; animID = character->playList()->getAnimation(MOVE); _CurrentSetup.AnimPlayed = animID; } float animSpeedFactor = 0.9f + 0.2f * NLMISC::frand(1); if (_PlayList) { if(_CopyAnim) { _PlayList->setTimeOrigin(MOVE, character->playList()->getTimeOrigin(MOVE)); if(character->playList()->getAnimation(MOVE)!=_PlayList->getAnimation(MOVE)) { _PlayList->setAnimation(MOVE, animID); _PlayList->setSpeedFactor(MOVE, character->playList()->getSpeedFactor(MOVE)); _PlayList->setWrapMode(MOVE, character->playList()->getWrapMode(MOVE)); } } else { _PlayList->setAnimation(MOVE, animID); _PlayList->setSpeedFactor(MOVE, animSpeedFactor); _PlayList->setTimeOrigin(MOVE, TimeInSec); _PlayList->setWrapMode(MOVE, UPlayList::Repeat); } } if (_FacePlayList) { uint faceAnimId=UPlayList::empty; if(_AnimationSet && animID<_AnimationSet->getNumAnimation()) { // build the anim name of the face string faceAnimName= COptionsAnimationSet::getFaceAnimName(_AnimationSet->getAnimationName(animID)); // find the face anim for this name faceAnimId= _AnimationSet->getAnimationIdByName(faceAnimName); if(faceAnimId==UAnimationSet::NotFound) faceAnimId= UPlayList::empty; } _FacePlayList->setAnimation(MOVE, faceAnimId); if(faceAnimId!=UPlayList::empty) { if(_CopyAnim) { _FacePlayList->setTimeOrigin(MOVE, character->facePlayList()->getTimeOrigin(MOVE)); _FacePlayList->setSpeedFactor(MOVE, character->facePlayList()->getSpeedFactor(MOVE)); _FacePlayList->setWrapMode(MOVE, character->facePlayList()->getWrapMode(MOVE)); } else { _FacePlayList->setSpeedFactor(MOVE, animSpeedFactor); _FacePlayList->setTimeOrigin(MOVE, TimeInSec); _FacePlayList->setWrapMode(MOVE, UPlayList::Repeat); } } } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::animate (double globalTime) { if (!_AnimationSet) return; _PlayListManager->animate (globalTime); animblink (globalTime); if (_CurrentSetup.AnimPlayed == -1) return; // take correct 3D animId uint animID= _CurrentSetup.AnimPlayed; bool applyRaceScalePos= true; if(!_CopyAnim) { if (_CurrentSetup.Male && animID < _AnimMale.size()) { applyRaceScalePos = _AnimMale[animID].ApplyRaceScalePos; // animId is now the correct 3D animId animID = _AnimMale[animID].AnimId; } else if (!_CurrentSetup.Male && animID < _AnimFemale.size()) { applyRaceScalePos = _AnimFemale[animID].ApplyRaceScalePos; // animId is now the correct 3D animId animID = _AnimFemale[animID].AnimId; } else return; } // get the animation if(animID==UAnimationSet::NotFound) return; UAnimation *pAnim = _AnimationSet->getAnimation (animID); if (pAnim == NULL) return; UTrack *pTrack = pAnim->getTrackByName("pos"); CVector animPos; if (pTrack == NULL) return; // Compute animation time (wrapped) double wrappedTime=(globalTime-_PlayList->getTimeOrigin(0))*_PlayList->getSpeedFactor(0); // Mod repeat the time { float length=pAnim->getEndTime ()-pAnim->getBeginTime(); if (wrappedTime>=0) wrappedTime=pAnim->getBeginTime()+(float)fmod ((float)wrappedTime, length); else wrappedTime=pAnim->getBeginTime()+(float)fmod ((float)wrappedTime, length)+length; } pTrack->interpolate((float)wrappedTime, animPos); // apply race scale pos only if animation need it if(applyRaceScalePos) animPos *= getGenderInfo(_CurrentSetup.People, _CurrentSetup.Male)->CharacterScalePos; // always apply custom scale pos animPos *= _CustomScalePos; _PelvisPos = animPos; // update skeleton pelvis pos if (!_Skeleton.empty()) { _Skeleton.setPos(_PelvisPos); // update skeleton spawn script pos _Skeleton.setSSSWOPos(_Root.getMatrix().getPos()); _Skeleton.setSSSWODir(_Root.getMatrix().getJ()); } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setPos (float x, float y, float z) { _CurPosX = x; _CurPosY = y; _CurPosZ = z; if (!_Root.empty()) _Root.setPos (x, y, z); } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setClusterSystem (NL3D::UInstanceGroup *pIG) { _ClusterSystem = pIG; if (!_Skeleton.empty()) _Skeleton.setClusterSystem(pIG); } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setRotEuler (float rx, float ry, float rz) { _CurRotX = rx; _CurRotY = ry; _CurRotZ = rz; if (!_Root.empty()) { _Root.setTransformMode (UTransformable::RotEuler); _Root.setRotEuler (_CurRotX, _CurRotY, _CurRotZ); } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::getHeadPos (float &x, float &y, float &z) { x = y = z = 0; if (!_Skeleton.empty()) { sint boneId = _Skeleton.getBoneIdByName("Bip01 Head"); if (boneId == -1) { nlwarning ("bad bone name"); return; } _Skeleton.forceComputeBone(boneId); UBone rBone = _Skeleton.getBone(boneId); const CMatrix &rM = rBone.getLastWorldMatrixComputed(); CVector v; rM.getPos(v); x = v.x; y = v.y; z = v.z; } else { nlwarning ("no skeleton"); } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::setSkeleton (const string &filename) { // Remove the old skeleton. if (!_Skeleton.empty()) { // Must remove first any channels of _Skeleton registered into _PlayList if (_PlayList) _PlayList->resetAllChannels(); _Scene->deleteSkeleton(_Skeleton); _Skeleton = NULL; _Root = NULL; } if (!_Root.empty()) _Scene->deleteTransform(_Root); _Root = _Scene->createTransform(); // Create the skeleton. _Skeleton = _Scene->createSkeleton(filename); if (_Skeleton.empty()) { nlwarning ("CCharacter3D::setSkeleton : Skeleton %s can't be created.", filename.c_str()); return; } _Skeleton.setPos (_PelvisPos); _Skeleton.changeMRMDistanceSetup (100.0f, 150.0f, 200.0f); _Skeleton.parent(_Root); } // ------------------------------------------------------------------------------------------------ void CCharacter3D::createInstance (TChar3DPart i, const SCharacter3DSetup::SCharacterPart &part) { if (_Scene == NULL) { nlwarning ("CCharacter3D::createInstance : no scene setup."); return; } if (!_Instances[i].empty()) _Scene->deleteInstance (_Instances[i]); if ((!part.Name.empty()) && (part.Name != "none.shape")) _Instances[i] = _Scene->createInstance (part.Name); // if cannot create output some errors if (_Instances[i].empty()) { if ((i != Char3DPart_HandRightItem) && (i != Char3DPart_HandLeftItem)) nlwarning ("CCharacter3D::createInstance : cannot create the instance : %s.", part.Name.c_str()); return; } // FX Management // Advantage Fx if (!_InstancesFx[i].AdvantageFx.empty()) _Scene->deleteInstance (_InstancesFx[i].AdvantageFx); if ((!part.AdvFx.empty()) && (part.AdvFx != "none.shape")) { _InstancesFx[i].AdvantageFx = _Scene->createInstance (part.AdvFx); if (_InstancesFx[i].AdvantageFx.empty()) { nlwarning ("CCharacter3D::createInstance : cannot create the fx : %s.", part.AdvFx.c_str()); } else { CMatrix mat = _Instances[i].getMatrix(); mat.invert(); mat *= _InstancesFx[i].AdvantageFx.getMatrix(); _InstancesFx[i].AdvantageFx.setTransformMode(UTransformable::DirectMatrix); _InstancesFx[i].AdvantageFx.setMatrix(mat); _InstancesFx[i].AdvantageFx.parent(_Instances[i]); } } // Static Fx uint32 fx; for (fx = 0; fx < _InstancesFx[i].StaticFx.size(); ++fx) if (!_InstancesFx[i].StaticFx[fx].empty()) _Scene->deleteInstance(_InstancesFx[i].StaticFx[fx]); _InstancesFx[i].StaticFx.clear(); for (fx = 0; fx < part.StatFxNames.size(); ++fx) if ((!part.StatFxNames[fx].empty()) && (part.StatFxNames[fx] != "none.shape") && (!part.StatFxBones[fx].empty()) && (part.StatFxBones[fx] != "none.shape")) { sint boneID = _Skeleton.getBoneIdByName(part.StatFxBones[fx]); if (boneID != -1) { UInstance instance = _Scene->createInstance(part.StatFxNames[fx]); if (!instance.empty()) { instance.setTransformMode(UTransform::DirectMatrix); CMatrix mat; mat.setPos(part.StatFxOffss[fx]); instance.setMatrix(mat); _Skeleton.stickObject(instance, boneID); _InstancesFx[i].StaticFx.push_back(instance); } else { nlwarning("Can't create static fx %s sticked on bone %s", part.StatFxNames[fx].c_str(), part.StatFxBones[fx].c_str()); } } else { nlwarning("Can't find bone %s for static fx %s", part.StatFxBones[fx].c_str(), part.StatFxNames[fx].c_str()); } } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::bindToSkeleton (TChar3DPart i) { if (_Skeleton.empty()) { nlwarning ("CCharacter3D::bindToSkeleton : no skeleton setup"); return; } if (_Instances[i].empty()) { if ((i != Char3DPart_HandRightItem) && (i != Char3DPart_HandLeftItem)) nlinfo ("CCharacter3D::bindToSkeleton : no character part for %d", i); return; } switch (i) { case Char3DPart_HandRightItem: { sint rightHandBoneID = _Skeleton.getBoneIdByName ("box_arme"); if (rightHandBoneID != -1) _Skeleton.stickObject (_Instances[i], rightHandBoneID); } break; case Char3DPart_HandLeftItem: { sint leftHandBoneID; // If this is a shield. if (_CurrentSetup.LeftHandItemIsShield) leftHandBoneID = _Skeleton.getBoneIdByName ("Box_bouclier"); else leftHandBoneID = _Skeleton.getBoneIdByName ("box_arme_gauche"); if (leftHandBoneID != -1) _Skeleton.stickObject (_Instances[i], leftHandBoneID); } break; default: if (!_Skeleton.bindSkin(_Instances[i])) { nlwarning ("CCharacter3D::bindToSkeleton: Cannot bind the instance : %d.", i); return; } break; } } // ------------------------------------------------------------------------------------------------ uint32 CCharacter3D::peopleToSkin (EGSPD::CPeople::TPeople people) const { switch (people) { case EGSPD::CPeople::Matis: return 1; case EGSPD::CPeople::Tryker: return 2; case EGSPD::CPeople::Zorai: return 3; case EGSPD::CPeople::Fyros: default: return 0; } } // ------------------------------------------------------------------------------------------------ void CCharacter3D::animblink (double globalTime) { float blend; // Some parameters static const double blinkTime = 0.1f; static const double minBlinkLength = 0.5f; static const double maxBlinkLength = 5.0f; // Next blink time is valid ? bool validTime = (_NextBlinkTime + blinkTime >= globalTime) && (_NextBlinkTime <= (globalTime + maxBlinkLength)); // Blink end ? bool blinkEnd = (globalTime >= _NextBlinkTime + blinkTime); // Blink is finished or next blink time is invalid ? if ( blinkEnd || !validTime ) { blend = 0; // Compute next time _NextBlinkTime = (((double)rand () / (double)RAND_MAX) * (maxBlinkLength - minBlinkLength) + minBlinkLength + (double)globalTime); } else { // Blink time ? if (globalTime >= _NextBlinkTime) { blend = 100.f; } else { // Do nothing return; } } // Set the blend shape if(!_Instances[Char3DPart_Face].empty()) _Instances[Char3DPart_Face].setBlendShapeFactor ("visage_100", blend, true); } // ------------------------------------------------------------------------------------------------ CVector CCharacter3D::getBonePos (const string &boneName) { CVector ret=CVector(0,0,0); sint boneId = _Skeleton.getBoneIdByName(boneName); if (boneId == -1) return ret; _Skeleton.forceComputeBone(boneId); UBone rBone = _Skeleton.getBone(boneId); const CMatrix &rM = rBone.getLastWorldMatrixComputed(); rM.getPos(ret); return ret; } // ------------------------------------------------------------------------------------------------