diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index d081f8a3e..47bc5f4da 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "data.hpp" @@ -16,6 +17,11 @@ namespace CSMWorld return mId; } + bool ActorAdapter::RaceData::isBeast() const + { + return mIsBeast; + } + bool ActorAdapter::RaceData::handlesPart(ESM::PartReferenceType type) const { switch (type) @@ -63,9 +69,10 @@ namespace CSMWorld if (!id.empty()) mDependencies.emplace(id); } - void ActorAdapter::RaceData::reset(const std::string& id) + void ActorAdapter::RaceData::reset_data(const std::string& id, bool isBeast) { mId = id; + mIsBeast = isBeast; for (auto& str : mFemaleParts) str.clear(); for (auto& str : mMaleParts) @@ -82,11 +89,28 @@ namespace CSMWorld return mId; } + bool ActorAdapter::ActorData::isCreature() const + { + return mCreature; + } + bool ActorAdapter::ActorData::isFemale() const { return mFemale; } + std::string ActorAdapter::ActorData::getSkeleton() const + { + if (mCreature || !mSkeletonOverride.empty()) + return "meshes\\" + mSkeletonOverride; + + bool firstPerson = false; + bool beast = mRaceData ? mRaceData->isBeast() : false; + bool werewolf = false; + + return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf); + } + const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index)) @@ -112,10 +136,12 @@ namespace CSMWorld if (!id.empty()) mDependencies.emplace(id); } - void ActorAdapter::ActorData::reset(const std::string& id, bool isFemale, RaceDataPtr raceData) + void ActorAdapter::ActorData::reset_data(const std::string& id, const std::string& skeleton, bool isCreature, bool isFemale, RaceDataPtr raceData) { mId = id; + mCreature = isCreature; mFemale = isFemale; + mSkeletonOverride = skeleton; mRaceData = raceData; for (auto& str : mParts) str.clear(); @@ -383,7 +409,7 @@ namespace CSMWorld if (index == -1) { // Record does not exist - data->reset(id); + data->reset_data(id); emit actorChanged(id); return; } @@ -392,7 +418,7 @@ namespace CSMWorld if (record.isDeleted()) { // Record is deleted and therefore not accessible - data->reset(id); + data->reset_data(id); emit actorChanged(id); return; } @@ -414,20 +440,18 @@ namespace CSMWorld else { // Wrong record type - data->reset(id); + data->reset_data(id); emit actorChanged(id); } } void ActorAdapter::setupRace(const std::string& id, RaceDataPtr data) { - // Common setup - data->reset(id); - int index = mRaces.searchId(id); if (index == -1) { // Record does not exist + data->reset_data(id); return; } @@ -435,10 +459,12 @@ namespace CSMWorld if (raceRecord.isDeleted()) { // Record is deleted, so not accessible + data->reset_data(id); return; } - // TODO move stuff in actor related to race here + auto& race = raceRecord.get(); + data->reset_data(id, race.mData.mFlags & ESM::Race::Beast); // Setup body parts for (int i = 0; i < mBodyParts.getSize(); ++i) @@ -470,7 +496,7 @@ namespace CSMWorld auto& npc = dynamic_cast&>(mReferenceables.getRecord(index)).get(); RaceDataPtr raceData = getRaceData(npc.mRace); - data->reset(id, !npc.isMale(), raceData); + data->reset_data(id, "", false, !npc.isMale(), raceData); // Add inventory items for (auto& item : npc.mInventory.mList) @@ -541,9 +567,11 @@ namespace CSMWorld void ActorAdapter::setupCreature(const std::string& id, ActorDataPtr data) { - data->reset(id); + // Record is known to exist and is not deleted + int index = mReferenceables.searchId(id); + auto& creature = dynamic_cast&>(mReferenceables.getRecord(index)).get(); - // TODO move stuff from Actor here + data->reset_data(id, creature.mModel, true); } void ActorAdapter::markDirtyDependency(const std::string& dep) diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index 0e8b0c9fe..ba714e840 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -44,6 +44,8 @@ namespace CSMWorld public: /// Retrieves the id of the race represented const std::string& getId() const; + /// Checks if it's a beast race + bool isBeast() const; /// Checks if a part could exist for the given type bool handlesPart(ESM::PartReferenceType type) const; /// Retrieves the associated body part @@ -60,11 +62,12 @@ namespace CSMWorld /// Marks an additional dependency void addOtherDependency(const std::string& id); /// Clears parts and dependencies - void reset(const std::string& raceId); + void reset_data(const std::string& raceId, bool isBeast=false); private: bool handles(ESM::PartReferenceType type) const; std::string mId; + bool mIsBeast; RacePartList mFemaleParts; RacePartList mMaleParts; StringSet mDependencies; @@ -78,8 +81,12 @@ namespace CSMWorld public: /// Retrieves the id of the actor represented const std::string& getId() const; + /// Checks if the actor is a creature + bool isCreature() const; /// Checks if the actor is female bool isFemale() const; + /// Returns the skeleton the actor should use for attaching parts to + std::string getSkeleton() const; /// Retrieves the associated actor part const std::string& getPart(ESM::PartReferenceType index) const; /// Checks if the actor has a data dependency @@ -90,11 +97,13 @@ namespace CSMWorld /// Marks an additional dependency for the actor void addOtherDependency(const std::string& id); /// Clears race, parts, and dependencies - void reset(const std::string& actorId, bool female=true, RaceDataPtr raceData=nullptr); + void reset_data(const std::string& actorId, const std::string& skeleton="", bool isCreature=false, bool female=true, RaceDataPtr raceData=nullptr); private: std::string mId; + bool mCreature; bool mFemale; + std::string mSkeletonOverride; RaceDataPtr mRaceData; ActorPartList mParts; StringSet mDependencies; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 0a2519d0d..7238166fc 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -18,15 +18,15 @@ namespace CSVRender { const std::string Actor::MeshPrefix = "meshes\\"; - Actor::Actor(const std::string& id, int type, CSMWorld::Data& data) + Actor::Actor(const std::string& id, CSMWorld::Data& data) : mId(id) - , mInitialized(false) - , mType(type) , mData(data) , mBaseNode(new osg::Group()) , mSkeleton(nullptr) { mActorData = mData.getActorAdapter()->getActorData(mId); + connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), + this, SLOT(handleActorChanged(const std::string&))); } osg::Group* Actor::getBaseNode() @@ -36,25 +36,33 @@ namespace CSVRender void Actor::update() { - try + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + + // Load skeleton + std::string skeletonModel = mActorData->getSkeleton(); + skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); + loadSkeleton(skeletonModel); + + if (!mActorData->isCreature()) { - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); + // Get rid of the extra attachments + SceneUtil::CleanObjectRootVisitor cleanVisitor; + mSkeleton->accept(cleanVisitor); + cleanVisitor.remove(); - if (mType == CSMWorld::UniversalId::Type_Npc) - updateNpc(); - else if (mType == CSMWorld::UniversalId::Type_Creature) - updateCreature(); + // Attach parts to skeleton + loadBodyParts(); } - catch (std::exception& e) + else { - Log(Debug::Info) << "Exception in Actor::update(): " << e.what(); + SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; + mSkeleton->accept(removeTriBipVisitor); + removeTriBipVisitor.remove(); } - if (!mInitialized) - { - mInitialized = true; - connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&))); - } + // Post setup + mSkeleton->markDirty(); + mSkeleton->setActive(SceneUtil::Skeleton::Active); } void Actor::handleActorChanged(const std::string& refId) @@ -65,57 +73,6 @@ namespace CSVRender } } - void Actor::updateCreature() - { - auto& referenceables = mData.getReferenceables(); - - auto& creature = dynamic_cast& >(referenceables.getRecord(mId)).get(); - - // Load skeleton with meshes - std::string skeletonModel = MeshPrefix + creature.mModel; - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); - loadSkeleton(skeletonModel); - - SceneUtil::RemoveTriBipVisitor removeTriBipVisitor; - mSkeleton->accept(removeTriBipVisitor); - removeTriBipVisitor.remove(); - - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); - } - - void Actor::updateNpc() - { - auto& races = mData.getRaces(); - auto& referenceables = mData.getReferenceables(); - - auto& npc = dynamic_cast& >(referenceables.getRecord(mId)).get(); - auto& race = dynamic_cast& >(races.getRecord(npc.mRace)).get(); - - bool is1stPerson = false; - bool isFemale = !npc.isMale(); - bool isBeast = race.mData.mFlags & ESM::Race::Beast; - bool isWerewolf = false; - - // Load skeleton - std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf); - skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS()); - loadSkeleton(skeletonModel); - - // Get rid of the extra attachments - SceneUtil::CleanObjectRootVisitor cleanVisitor; - mSkeleton->accept(cleanVisitor); - cleanVisitor.remove(); - - // Attach parts to skeleton - loadBodyParts(npc.mId); - - // Post setup - mSkeleton->markDirty(); - mSkeleton->setActive(SceneUtil::Skeleton::Active); - } - void Actor::loadSkeleton(const std::string& model) { auto sceneMgr = mData.getResourceSystem()->getSceneManager(); @@ -136,7 +93,7 @@ namespace CSVRender } - void Actor::loadBodyParts(const std::string& actorId) + void Actor::loadBodyParts() { for (int i = 0; i < ESM::PRT_Count; ++i) { diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index d7cbb3067..2f19454f7 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -38,7 +38,7 @@ namespace CSVRender /// \param id The referenceable id /// \param type The record type /// \param data The data store - Actor(const std::string& id, int type, CSMWorld::Data& data); + Actor(const std::string& id, CSMWorld::Data& data); /// Retrieves the base node that meshes are attached to osg::Group* getBaseNode(); @@ -50,11 +50,8 @@ namespace CSVRender void handleActorChanged(const std::string& refId); private: - void updateCreature(); - void updateNpc(); - void loadSkeleton(const std::string& model); - void loadBodyParts(const std::string& actorId); + void loadBodyParts(); void attachBodyPart(ESM::PartReferenceType, const std::string& mesh); std::string getBodyPartMesh(const std::string& bodyPartId); @@ -62,8 +59,6 @@ namespace CSVRender static const std::string MeshPrefix; std::string mId; - bool mInitialized; - int mType; CSMWorld::Data& mData; CSMWorld::ActorAdapter::ActorDataPtr mActorData; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 63f1bc8a8..6f0fb6606 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -83,74 +83,58 @@ void CSVRender::Object::update() { clear(); - std::string model; - int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh - const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables(); + const int TypeIndex = referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType); + const int ModelIndex = referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model); int index = referenceables.searchId (mReferenceableId); - int recordType = -1; const ESM::Light* light = NULL; - if (index==-1) - error = 1; - else - { - /// \todo check for Deleted state (error 1) + mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - model = referenceables.getData (index, - referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)). - toString().toUtf8().constData(); + if (index == -1) + { + mBaseNode->addChild(createErrorCube()); + return; + } - recordType = - referenceables.getData (index, - referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt(); - if (recordType == CSMWorld::UniversalId::Type_Light) - { - light = &dynamic_cast& >(referenceables.getRecord(index)).get(); - if (model.empty()) - model = "marker_light.nif"; - } + /// \todo check for Deleted state (error 1) - if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList) - { - if (model.empty()) - model = "marker_creature.nif"; - } + int recordType = referenceables.getData(index, TypeIndex).toInt(); + std::string model = referenceables.getData(index, ModelIndex).toString().toUtf8().constData(); - if (recordType != CSMWorld::UniversalId::Type_Npc && model.empty()) - error = 2; + if (recordType == CSMWorld::UniversalId::Type_Light) + { + light = &dynamic_cast& >(referenceables.getRecord(index)).get(); + if (model.empty()) + model = "marker_light.nif"; } - mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); - - if (error) + if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList) { - mBaseNode->addChild(createErrorCube()); + if (model.empty()) + model = "marker_creature.nif"; } - else + + try { - try + if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) { - if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature) - { - if (!mActor) - mActor.reset(new Actor(mReferenceableId, recordType, mData)); - mActor->update(); - mBaseNode->addChild(mActor->getBaseNode()); - } - else - { - std::string path = "meshes\\" + model; - mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); - } + if (!mActor) mActor.reset(new Actor(mReferenceableId, mData)); + mActor->update(); + mBaseNode->addChild(mActor->getBaseNode()); } - catch (std::exception& e) + else { - Log(Debug::Error) << e.what(); - mBaseNode->addChild(createErrorCube()); + std::string path = "meshes\\" + model; + mResourceSystem->getSceneManager()->getInstance(path, mBaseNode); } } + catch (std::exception& e) + { + // TODO: use error marker mesh + Log(Debug::Error) << e.what(); + } if (light) {