#include "npcanimation.hpp" #include "../mwworld/world.hpp" #include "renderconst.hpp" using namespace Ogre; using namespace NifOgre; namespace MWRender{ NpcAnimation::~NpcAnimation(){ } NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ ESMS::LiveCellRef *ref = ptr.get(); Ogre::Entity* blank = 0; std::vector* blankshape = 0; chest = std::make_pair(blank, blankshape); tail = std::make_pair(blank, blankshape); lBeastFoot = std::make_pair(blank, blankshape); rBeastFoot = std::make_pair(blank, blankshape); rhand = std::make_pair(blank, blankshape); lhand = std::make_pair(blank, blankshape); skirt = std::make_pair(blank, blankshape); //Part selection on last character of the file string // " Tri Chest // * Tri Tail // : Tri Left Foot // < Tri Right Foot // > Tri Left Hand // ? Tri Right Hand // | Normal //Mirroring Parts on second to last character //suffix == '*' // vector = Ogre::Vector3(-1,1,1); // suffix == '?' // vector = Ogre::Vector3(1,-1,1); // suffix == '<' // vector = Ogre::Vector3(1,1,-1); hairID = ref->base->hair; headID = ref->base->head; npcName = ref->base->name; //ESMStore::Races r = const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2); bool female = tolower(secondtolast) == 'f'; std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); isBeast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; /*std::cout << "Race: " << ref->base->race ; if(female){ std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; } else{ std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; }*/ std::string smodel = "meshes\\base_anim.nif"; if(isBeast) smodel = "meshes\\base_animkna.nif"; insert = ptr.getRefData().getBaseNode(); assert(insert); NifOgre::NIFLoader::load(smodel); base = mRend.getScene()->createEntity(smodel); base->setVisibilityFlags(RV_Actors); bool transparent = false; for (unsigned int i=0; igetNumSubEntities(); ++i) { Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); while (techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); if (pass->getDepthWriteEnabled() == false) transparent = true; } } } base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones //stay in the same place when we skipanim, or open a gui window if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){ for(unsigned int init = 0; init < transformations->size(); init++){ rindexI.push_back(0); tindexI.push_back(0); } stopTime = transformations->begin()->getStopTime(); startTime = transformations->begin()->getStartTime(); } textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel); insert->attachObject(base); if(female) insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); else insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); std::cout << "Inv" << inv.getStateId() << "\n"; updateParts(); } void NpcAnimation::updateParts(){ std::string headModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; std::string hairModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ //A robe was added or removed if(chest.first) { insert->detachObject(chest.first); chest.first = 0; } robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); if(robe != inv.end()) { MWWorld::Ptr ptr = *robe; const ESM::Clothing *clothes = (ptr.get())->base; std::vector parts = clothes->parts.parts; for(int i = 0; i < parts.size(); i++) { ESM::PartReference part = parts[i]; if(part.part == ESM::PRT_Cuirass) { const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); chest = insertFreePart("meshes\\" + bodypart->model, ":\""); } } } } if(robe == inv.end() ){ //if(inv.getSlot(MWWorld::InventoryStore::Cuirass) != inv.end()) if(chest.first == 0){ const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); chest = insertFreePart("meshes\\" + chestPart->model, ":\""); } } } Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ NIFLoader::load(mesh); Ogre::Entity* part = mRend.getScene()->createEntity(mesh); base->attachObjectToBone(bonename, part); return part; } std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix){ std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix; NIFLoader::load(meshNumbered); Ogre::Entity* part = mRend.getScene()->createEntity(meshNumbered); insert->attachObject(part); std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix)); if(shape){ handleShapes(shape, part, base->getSkeleton()); } std::pair*> pair = std::make_pair(part, shape); return pair; } void NpcAnimation::runAnimation(float timepassed){ if(timeToChange > .2){ timeToChange = 0; updateParts(); } timeToChange += timepassed; //1. Add the amount of time passed to time //2. Handle the animation transforms dependent on time //3. Handle the shapes dependent on animation transforms if(animate > 0){ time += timepassed; if(time > stopTime){ animate--; if(animate == 0) time = stopTime; else time = startTime + (time - stopTime); } handleAnimationTransforms(); vecRotPos.clear(); if(lBeastFoot.first) handleShapes(lBeastFoot.second, lBeastFoot.first, base->getSkeleton()); if(rBeastFoot.first) handleShapes(rBeastFoot.second, rBeastFoot.first, base->getSkeleton()); if(chest.first) handleShapes(chest.second, chest.first, base->getSkeleton()); if(tail.first) handleShapes(tail.second, tail.first, base->getSkeleton()); if(skirt.first) handleShapes(skirt.second, skirt.first, base->getSkeleton()); if(lhand.first) handleShapes(lhand.second, lhand.first, base->getSkeleton()); if(rhand.first) handleShapes(rhand.second, rhand.first, base->getSkeleton()); } } }