From d47de55ce9d017485934b08d354306a8041f1b19 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 15:19:39 +0200 Subject: [PATCH 01/22] read info records --- components/esm/records.hpp | 2 +- components/esm_store/store.cpp | 72 +++++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 4ef8ce564..fb5733c63 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -14,13 +14,13 @@ #include "loadcont.hpp" #include "loadcrea.hpp" #include "loadcrec.hpp" +#include "loadinfo.hpp" #include "loaddial.hpp" #include "loaddoor.hpp" #include "loadench.hpp" #include "loadfact.hpp" #include "loadglob.hpp" #include "loadgmst.hpp" -#include "loadinfo.hpp" #include "loadingr.hpp" #include "loadland.hpp" #include "loadlevlist.hpp" diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index 2016272e0..622676689 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -18,32 +18,68 @@ static string toStr(int i) void ESMStore::load(ESMReader &esm) { - set missing; + set missing; - // Loop through all records - while(esm.hasMoreRecs()) + ESM::Dialogue *dialogue = 0; + + // Loop through all records + while(esm.hasMoreRecs()) { - NAME n = esm.getRecName(); - esm.getRecHeader(); + NAME n = esm.getRecName(); + esm.getRecHeader(); - // Look up the record type. - RecListList::iterator it = recLists.find(n.val); + // Look up the record type. + RecListList::iterator it = recLists.find(n.val); - if(it == recLists.end()) + if(it == recLists.end()) { - // Not found (this would be an error later) - esm.skipRecord(); - missing.insert(n.toString()); - continue; + if (n.val==ESM::REC_INFO) + { + if (dialogue) + { + ESM::DialInfo info; + info.load (esm); + } + else + { + std::cerr << "error: info record without dialog" << std::endl; + esm.skipRecord(); + continue; + } + } + else + { + // Not found (this would be an error later) + esm.skipRecord(); + missing.insert(n.toString()); + continue; + } } + else + { + // Load it + std::string id = esm.getHNOString("NAME"); + it->second->load(esm, id); + + if (n.val==ESM::REC_DIAL) + { + RecListT& recList = static_cast& > (*it->second); + + id = recList.toLower (id); - // Load it - std::string id = esm.getHNOString("NAME"); - it->second->load(esm, id); + RecListT::MapType::iterator iter = recList.list.find (id); - // Insert the reference into the global lookup - if(!id.empty()) - all[id] = n.val; + assert (iter!=recList.list.end()); + + dialogue = &iter->second; + } + else + dialogue = 0; + + // Insert the reference into the global lookup + if(!id.empty()) + all[id] = n.val; + } } /* This information isn't needed on screen. But keep the code around From 6b1b3b20fda3b2286a2a0840347c0b1a907f5d88 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 15:23:13 +0200 Subject: [PATCH 02/22] store info records in dialogue records --- components/esm/loaddial.hpp | 4 ++++ components/esm_store/store.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 4c80fc783..c435eb276 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -1,7 +1,10 @@ #ifndef _ESM_DIAL_H #define _ESM_DIAL_H +#include + #include "esm_reader.hpp" +#include "loadinfo.hpp" namespace ESM { @@ -23,6 +26,7 @@ struct Dialogue }; char type; + std::vector mInfo; void load(ESMReader &esm) { diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index 622676689..c43855873 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -39,6 +39,8 @@ void ESMStore::load(ESMReader &esm) { ESM::DialInfo info; info.load (esm); + + dialogue->mInfo.push_back (info); } else { From 761157206548a33a3aa84c2177e75b195138ca5e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 15:25:54 +0200 Subject: [PATCH 03/22] cleanup --- components/esm_store/store.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/esm_store/store.hpp b/components/esm_store/store.hpp index fd4a47d4b..02b526492 100644 --- a/components/esm_store/store.hpp +++ b/components/esm_store/store.hpp @@ -69,7 +69,6 @@ namespace ESMS // Lists that need special rules CellList cells; RecIDListT gameSettings; - //RecListT dialInfos; //RecListT lands; //RecListT landTexts; //RecListT magicEffects; @@ -92,7 +91,6 @@ namespace ESMS ESMStore() { - recLists[REC_ACTI] = &activators; recLists[REC_ACTI] = &activators; recLists[REC_ALCH] = &potions; recLists[REC_APPA] = &appas; @@ -113,7 +111,6 @@ namespace ESMS recLists[REC_FACT] = &factions; recLists[REC_GLOB] = &globals; recLists[REC_GMST] = &gameSettings; - //recLists[REC_INFO] = &dialInfos; recLists[REC_INGR] = &ingreds; //recLists[REC_LAND] = &lands; recLists[REC_LEVC] = &creatureLists; From 8045320ac94c507c805f511d599d2846b5afd1c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 18:01:34 +0200 Subject: [PATCH 04/22] added dialog manager --- apps/openmw/CMakeLists.txt | 12 ++++++++++-- apps/openmw/engine.cpp | 6 ++++++ apps/openmw/mwdialog/dialogmanager.cpp | 17 +++++++++++++++++ apps/openmw/mwdialog/dialogmanager.hpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwworld/environment.hpp | 11 ++++++++--- 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 apps/openmw/mwdialog/dialogmanager.cpp create mode 100644 apps/openmw/mwdialog/dialogmanager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c9112b0ee..f07143be5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,6 +41,14 @@ set(GAMEGUI ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) +set(GAMEDIALOG_HEADER + mwdialog/dialogmanager.hpp +) +set(GAMEDIALOG + mwdialog/dialogmanager.cpp +) +source_group(apps\\openmw\\mwdialog FILES ${GAMEDIALOG_HEADER} ${GAMEDIALOG}) + set(GAMESCRIPT mwscript/scriptmanager.cpp mwscript/compilercontext.cpp @@ -154,11 +162,11 @@ set(GAMEMECHANICS_HEADER source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD} - ${GAMECLASS} ${GAMEMECHANICS} + ${GAMECLASS} ${GAMEMECHANICS} ${GAMEDIALOG} ) set(OPENMW_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER} ${GAMESCRIPT_HEADER} ${GAMESOUND_HEADER} ${GAMEGUI_HEADER} ${GAMEWORLD_HEADER} ${GAMECLASS_HEADER} - ${GAMEMECHANICS_HEADER} + ${GAMEMECHANICS_HEADER} ${GAMEDIALOG_HEADER} ) # Main executable diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b67bcd0ac..2cd738623 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -28,6 +28,8 @@ #include "mwclass/classes.hpp" +#include "mwdialog/dialogmanager.hpp" + #include "mwmechanics/mechanicsmanager.hpp" #include @@ -117,6 +119,7 @@ OMW::Engine::~Engine() delete mEnvironment.mSoundManager; delete mEnvironment.mGlobalScripts; delete mEnvironment.mMechanicsManager; + delete mEnvironment.mDialogManager; delete mScriptManager; delete mScriptContext; } @@ -250,6 +253,9 @@ void OMW::Engine::go() mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager ( mEnvironment.mWorld->getStore(), *mEnvironment.mWindowManager); + // Create dialog system + mEnvironment.mDialogManager = new MWDialog::DialogManager (mEnvironment); + // load cell ESM::Position pos; pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; diff --git a/apps/openmw/mwdialog/dialogmanager.cpp b/apps/openmw/mwdialog/dialogmanager.cpp new file mode 100644 index 000000000..2dfaebb76 --- /dev/null +++ b/apps/openmw/mwdialog/dialogmanager.cpp @@ -0,0 +1,17 @@ + +#include "dialogmanager.hpp" + +#include "../mwworld/class.hpp" + +#include + +namespace MWDialog +{ + DialogManager::DialogManager (MWWorld::Environment& environment) : mEnvironment (environment) {} + + void DialogManager::startDialog (const MWWorld::Ptr& actor) + { + std::cout << "talking with " << MWWorld::Class::get (actor).getName (actor) << std::endl; + } + +} diff --git a/apps/openmw/mwdialog/dialogmanager.hpp b/apps/openmw/mwdialog/dialogmanager.hpp new file mode 100644 index 000000000..8f4067c9a --- /dev/null +++ b/apps/openmw/mwdialog/dialogmanager.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MMDIALOG_DIALOGMANAGER_H +#define GAME_MWDIALOG_DIALOGMANAGER_H + +#include "../mwworld/ptr.hpp" + +namespace MWWorld +{ + class Environment; +} + +namespace MWDialog +{ + class DialogManager + { + MWWorld::Environment& mEnvironment; + + public: + + DialogManager (MWWorld::Environment& environment); + + void startDialog (const MWWorld::Ptr& actor); + + }; +} + +#endif diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index 0c6476d52..1887e619f 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -21,17 +21,22 @@ namespace MWMechanics class MechanicsManager; } +namespace MWDialog +{ + class DialogManager; +} + namespace MWWorld { class World; ///< Collection of script-accessable sub-systems class Environment - { + { public: Environment() : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), - mMechanicsManager (0), mFrameDuration (0) + mMechanicsManager (0), mDialogManager (0), mFrameDuration (0) {} World *mWorld; @@ -39,9 +44,9 @@ namespace MWWorld MWScript::GlobalScripts *mGlobalScripts; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; + MWDialog::DialogManager *mDialogManager; float mFrameDuration; }; } #endif - From d6541d4f3cdc4b2003c7ee9d8e2e504999d85d9b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 19:10:56 +0200 Subject: [PATCH 05/22] changed file names to ensure consistent spelling --- apps/openmw/CMakeLists.txt | 14 +++++++------- apps/openmw/engine.cpp | 2 +- .../dialoguemanager.cpp} | 2 +- .../dialoguemanager.hpp} | 0 4 files changed, 9 insertions(+), 9 deletions(-) rename apps/openmw/{mwdialog/dialogmanager.cpp => mwdialogue/dialoguemanager.cpp} (91%) rename apps/openmw/{mwdialog/dialogmanager.hpp => mwdialogue/dialoguemanager.hpp} (100%) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f07143be5..d27ddae2d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,13 +41,13 @@ set(GAMEGUI ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) -set(GAMEDIALOG_HEADER - mwdialog/dialogmanager.hpp +set(GAMEDIALOGUE_HEADER + mwdialogue/dialoguemanager.hpp ) -set(GAMEDIALOG - mwdialog/dialogmanager.cpp +set(GAMEDIALOGUE + mwdialogue/dialoguemanager.cpp ) -source_group(apps\\openmw\\mwdialog FILES ${GAMEDIALOG_HEADER} ${GAMEDIALOG}) +source_group(apps\\openmw\\mwdialogue FILES ${GAMEDIALOGUE_HEADER} ${GAMEDIALOGUE}) set(GAMESCRIPT mwscript/scriptmanager.cpp @@ -162,11 +162,11 @@ set(GAMEMECHANICS_HEADER source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER}) set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD} - ${GAMECLASS} ${GAMEMECHANICS} ${GAMEDIALOG} + ${GAMECLASS} ${GAMEMECHANICS} ${GAMEDIALOGUE} ) set(OPENMW_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER} ${GAMESCRIPT_HEADER} ${GAMESOUND_HEADER} ${GAMEGUI_HEADER} ${GAMEWORLD_HEADER} ${GAMECLASS_HEADER} - ${GAMEMECHANICS_HEADER} ${GAMEDIALOG_HEADER} + ${GAMEMECHANICS_HEADER} ${GAMEDIALOG_HEADERUE} ) # Main executable diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2cd738623..35200b2d1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -28,7 +28,7 @@ #include "mwclass/classes.hpp" -#include "mwdialog/dialogmanager.hpp" +#include "mwdialogue/dialoguemanager.hpp" #include "mwmechanics/mechanicsmanager.hpp" diff --git a/apps/openmw/mwdialog/dialogmanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp similarity index 91% rename from apps/openmw/mwdialog/dialogmanager.cpp rename to apps/openmw/mwdialogue/dialoguemanager.cpp index 2dfaebb76..d00c0aa83 100644 --- a/apps/openmw/mwdialog/dialogmanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -1,5 +1,5 @@ -#include "dialogmanager.hpp" +#include "dialoguemanager.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwdialog/dialogmanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp similarity index 100% rename from apps/openmw/mwdialog/dialogmanager.hpp rename to apps/openmw/mwdialogue/dialoguemanager.hpp From c806415f08389034a12036c12740a6f115a6e3f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 19:16:44 +0200 Subject: [PATCH 06/22] changed namespace, class and function names to ensure consistent spelling --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwdialogue/dialoguemanager.cpp | 6 +++--- apps/openmw/mwdialogue/dialoguemanager.hpp | 12 ++++++------ apps/openmw/mwworld/environment.hpp | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 35200b2d1..396e4bad1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -119,7 +119,7 @@ OMW::Engine::~Engine() delete mEnvironment.mSoundManager; delete mEnvironment.mGlobalScripts; delete mEnvironment.mMechanicsManager; - delete mEnvironment.mDialogManager; + delete mEnvironment.mDialogueManager; delete mScriptManager; delete mScriptContext; } @@ -254,7 +254,7 @@ void OMW::Engine::go() mEnvironment.mWorld->getStore(), *mEnvironment.mWindowManager); // Create dialog system - mEnvironment.mDialogManager = new MWDialog::DialogManager (mEnvironment); + mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment); // load cell ESM::Position pos; diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index d00c0aa83..22602a3f7 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -5,11 +5,11 @@ #include -namespace MWDialog +namespace MWDialogue { - DialogManager::DialogManager (MWWorld::Environment& environment) : mEnvironment (environment) {} + DialogueManager::DialogueManager (MWWorld::Environment& environment) : mEnvironment (environment) {} - void DialogManager::startDialog (const MWWorld::Ptr& actor) + void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { std::cout << "talking with " << MWWorld::Class::get (actor).getName (actor) << std::endl; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index 8f4067c9a..b31a3d063 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MMDIALOG_DIALOGMANAGER_H -#define GAME_MWDIALOG_DIALOGMANAGER_H +#ifndef GAME_MMDIALOG_DIALOGUEMANAGER_H +#define GAME_MWDIALOG_DIALOGUEMANAGER_H #include "../mwworld/ptr.hpp" @@ -8,17 +8,17 @@ namespace MWWorld class Environment; } -namespace MWDialog +namespace MWDialogue { - class DialogManager + class DialogueManager { MWWorld::Environment& mEnvironment; public: - DialogManager (MWWorld::Environment& environment); + DialogueManager (MWWorld::Environment& environment); - void startDialog (const MWWorld::Ptr& actor); + void startDialogue (const MWWorld::Ptr& actor); }; } diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index 1887e619f..f9e2e8a42 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -21,9 +21,9 @@ namespace MWMechanics class MechanicsManager; } -namespace MWDialog +namespace MWDialogue { - class DialogManager; + class DialogueManager; } namespace MWWorld @@ -36,7 +36,7 @@ namespace MWWorld public: Environment() : mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0), - mMechanicsManager (0), mDialogManager (0), mFrameDuration (0) + mMechanicsManager (0), mDialogueManager (0), mFrameDuration (0) {} World *mWorld; @@ -44,7 +44,7 @@ namespace MWWorld MWScript::GlobalScripts *mGlobalScripts; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; - MWDialog::DialogManager *mDialogManager; + MWDialogue::DialogueManager *mDialogueManager; float mFrameDuration; }; } From b5d59edd446c5c3bbea7cea93c1c0d762b826abf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 6 Aug 2010 19:25:26 +0200 Subject: [PATCH 07/22] re-routed talk action from gui to dialogue manager (master branch should not incooperate this change, because the dialogue window implementer will need the original code for testing) --- apps/openmw/mwworld/actiontalk.cpp | 4 ++-- apps/openmw/mwworld/actiontalk.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 2b4aba735..7d38c22fd 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,7 +3,7 @@ #include "environment.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwdialogue/dialoguemanager.hpp" namespace MWWorld { @@ -11,6 +11,6 @@ namespace MWWorld void ActionTalk::execute (Environment& environment) { - environment.mWindowManager->setMode (MWGui::GM_Dialogue); + environment.mDialogueManager->startDialogue (mActor); } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index 034d6131c..a60a61660 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -13,6 +13,7 @@ namespace MWWorld public: ActionTalk (const Ptr& actor); + ///< \param actor The actor the player is talking to virtual void execute (Environment& environment); }; From 305563e5952abaea5481464da3fa58b121870fc6 Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Sun, 8 Aug 2010 10:07:02 +0200 Subject: [PATCH 08/22] disabled char encoding method for windows, although you'll need to add the iconv libs --- cmake/FindIconv.cmake | 5 ++ components/esm/esm_reader.hpp | 147 ++++++++++++++++++---------------- 2 files changed, 82 insertions(+), 70 deletions(-) diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake index 000e09b84..571a959af 100644 --- a/cmake/FindIconv.cmake +++ b/cmake/FindIconv.cmake @@ -14,6 +14,11 @@ IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) SET(ICONV_FIND_QUIETLY TRUE) ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) +IF(WIN32) + SET(ICONV_INCLUDE_DIR $ENV{ICONV_INCLUDE_DIR}) + SET(ICONV_LIBRARIES $ENV{ICONV_LIBRARIES}) +ENDIF(WIN32) + FIND_PATH(ICONV_INCLUDE_DIR iconv.h) FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c) diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 70a81e6f4..32f5570ad 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -9,7 +9,10 @@ #include #include #include -#include + +#ifndef __WIN32__ + #include +#endif #include #include @@ -618,89 +621,93 @@ public: return convertToUTF8(res); } - // Convert a string from the encoding used by Morrowind to UTF-8 - std::string convertToUTF8(std::string input) - { - std::string output = ""; - - //create convert description - iconv_t cd = iconv_open("UTF-8", "WINDOWS-1252"); - - if (cd == (iconv_t)-1) //error handling - { - std::string errMsg = "Creating description for UTF-8 converting failed: "; - - switch (errno) //detailed error messages (maybe it contains too much detail :) - { - case EMFILE: - errMsg += "{OPEN_MAX} files descriptors are currently open in the calling process."; - case ENFILE: - errMsg += "Too many files are currently open in the system."; - case ENOMEM: - errMsg +="Insufficient storage space is available."; - case EINVAL: - errMsg += "The conversion specified by fromcode and tocode is not supported by the implementation."; - - default: - errMsg += "Unknown Error\n"; - } - - fail(errMsg); - - } - else + // Convert a string from the encoding used by Morrowind to UTF-8 + std::string convertToUTF8 (std::string input) { - const size_t inputSize = input.size(); +#ifdef __WIN32__ + return input; +#else + std::string output = ""; - if (inputSize) //input is not empty - { - //convert function doesn't accept const char *, therefore copy content into an char * - std::vector inputBuffer(input.begin(), input.end()); - char *inputBufferBegin = &inputBuffer[0]; + //create convert description + iconv_t cd = iconv_open ("UTF-8", "WINDOWS-1252"); - size_t inputBytesLeft = inputSize; //bytes to convert + if (cd == (iconv_t)-1) //error handling + { + std::string errMsg = "Creating description for UTF-8 converting failed: "; - static const size_t outputSize = 1000; - size_t outputBytesLeft; + switch (errno) //detailed error messages (maybe it contains too much detail :) + { + case EMFILE: + errMsg += "{OPEN_MAX} files descriptors are currently open in the calling process."; + case ENFILE: + errMsg += "Too many files are currently open in the system."; + case ENOMEM: + errMsg +="Insufficient storage space is available."; + case EINVAL: + errMsg += "The conversion specified by fromcode and tocode is not supported by the implementation."; + + default: + errMsg += "Unknown Error\n"; + } - char outputBuffer[outputSize]; - char *outputBufferBegin; + fail (errMsg); - while (inputBytesLeft > 0 ) + } + else { - outputBytesLeft = outputSize; - outputBufferBegin = outputBuffer; + const size_t inputSize = input.size(); - if (iconv(cd, &inputBufferBegin, &inputBytesLeft, &outputBufferBegin, &outputBytesLeft) == (size_t)-1) - { - switch (errno) + if (inputSize) //input is not empty { - case E2BIG: //outputBuffer is full - output += std::string(outputBuffer, outputSize); - break; - case EILSEQ: - fail("Iconv: Invalid multibyte sequence.\n"); - break; - case EINVAL: - fail("Iconv: Incomplete multibyte sequence.\n"); - break; - default: - fail("Iconv: Unknown Error\n"); - } + //convert function doesn't accept const char *, therefore copy content into an char * + std::vector inputBuffer (input.begin(), input.end()); + char *inputBufferBegin = &inputBuffer[0]; + + size_t inputBytesLeft = inputSize; //bytes to convert + + static const size_t outputSize = 1000; + size_t outputBytesLeft; + + char outputBuffer[outputSize]; + char *outputBufferBegin; + + while (inputBytesLeft > 0) + { + outputBytesLeft = outputSize; + outputBufferBegin = outputBuffer; + + if (iconv (cd, &inputBufferBegin, &inputBytesLeft, &outputBufferBegin, &outputBytesLeft) == (size_t)-1) + { + switch (errno) + { + case E2BIG: //outputBuffer is full + output += std::string (outputBuffer, outputSize); + break; + case EILSEQ: + fail ("Iconv: Invalid multibyte sequence.\n"); + break; + case EINVAL: + fail ("Iconv: Incomplete multibyte sequence.\n"); + break; + default: + fail ("Iconv: Unknown Error\n"); + } + + } + } + + //read only relevant bytes from outputBuffer + output += std::string (outputBuffer, outputSize - outputBytesLeft); - } + } } - //read only relevant bytes from outputBuffer - output += std::string(outputBuffer, outputSize - outputBytesLeft); + iconv_close (cd); - } + return output; } - - iconv_close (cd); - - return output; - } +#endif void skip(int bytes) { esm->seek(esm->tell()+bytes); } uint64_t getOffset() { return esm->tell(); } From 9d25e74a051837a1f70dc09b35d55573d0941829 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 11:34:03 +0200 Subject: [PATCH 09/22] on dialogue start run through the info records of dialogue record 'hello'; currently no testing done -> the first info recrod will match --- apps/openmw/mwdialogue/dialoguemanager.cpp | 61 ++++++++++++++++++++++ apps/openmw/mwdialogue/dialoguemanager.hpp | 7 +++ 2 files changed, 68 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 22602a3f7..c11e2bb0d 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -1,17 +1,78 @@ #include "dialoguemanager.hpp" +#include +#include + +#include + #include "../mwworld/class.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" #include namespace MWDialogue { + bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const + { + // TODO check actor id + // TODO check actor race + // TODO check actor class + // TODO check actor faction + // TODO check player faction + // TODO check cell + // TODO check DATAstruct + // TODO check select structures + + std::cout + << "unchecked entries:" << std::endl + << " actor id: " << info.actor << std::endl + << " actor race: " << info.race << std::endl + << " actor class: " << info.clas << std::endl + << " actor faction: " << info.npcFaction << std::endl + << " player faction: " << info.pcFaction << std::endl + << " cell: " << info.cell << std::endl + << " DATAstruct" << std::endl; + + for (std::vector::const_iterator iter (info.selects.begin()); + iter != info.selects.end(); ++iter) + std::cout << " select: " << iter->selectRule << std::endl; + + return true; + } + DialogueManager::DialogueManager (MWWorld::Environment& environment) : mEnvironment (environment) {} void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { std::cout << "talking with " << MWWorld::Class::get (actor).getName (actor) << std::endl; + + const ESM::Dialogue *dialogue = mEnvironment.mWorld->getStore().dialogs.find ("hello"); + + for (std::vector::const_iterator iter (dialogue->mInfo.begin()); + iter!=dialogue->mInfo.end(); ++iter) + { + if (isMatching (actor, *iter)) + { + // start dialogue + std::cout << "found matching info record" << std::endl; + + std::cout << "response: " << iter->response << std::endl; + + if (!iter->sound.empty()) + { + // TODO play sound + } + + if (!iter->resultScript.empty()) + { + // TODO execute script + } + + break; + } + } } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index b31a3d063..d51570b11 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -3,6 +3,11 @@ #include "../mwworld/ptr.hpp" +namespace ESM +{ + struct DialInfo; +} + namespace MWWorld { class Environment; @@ -14,6 +19,8 @@ namespace MWDialogue { MWWorld::Environment& mEnvironment; + bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; + public: DialogueManager (MWWorld::Environment& environment); From a25c7bb2c07cbf00cb12e0dc8082947c4d1a9d0a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 11:37:59 +0200 Subject: [PATCH 10/22] added test for cell name --- apps/openmw/mwdialogue/dialoguemanager.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index c11e2bb0d..941c760e7 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -21,7 +21,12 @@ namespace MWDialogue // TODO check actor class // TODO check actor faction // TODO check player faction - // TODO check cell + + // check cell + if (!info.cell.empty()) + if (mEnvironment.mWorld->getPlayerPos().getPlayer().getCell()->cell->name != info.cell) + return false; + // TODO check DATAstruct // TODO check select structures @@ -32,7 +37,6 @@ namespace MWDialogue << " actor class: " << info.clas << std::endl << " actor faction: " << info.npcFaction << std::endl << " player faction: " << info.pcFaction << std::endl - << " cell: " << info.cell << std::endl << " DATAstruct" << std::endl; for (std::vector::const_iterator iter (info.selects.begin()); From 8f4359db08d7ccce87a6723ba41e24d51afa5276 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 13:21:03 +0200 Subject: [PATCH 11/22] added test for select type '3' (Local) --- apps/openmw/mwdialogue/dialoguemanager.cpp | 110 +++++++++++++++++++-- apps/openmw/mwdialogue/dialoguemanager.hpp | 9 +- 2 files changed, 108 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 941c760e7..4f9cf602f 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -1,7 +1,6 @@ #include "dialoguemanager.hpp" -#include #include #include @@ -9,11 +8,110 @@ #include "../mwworld/class.hpp" #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwworld/refdata.hpp" #include +namespace +{ + template + bool selectCompare (char comp, T1 value1, T2 value2) + { + switch (comp) + { + case '0': return value1==value2; + case '1': return value1!=value2; + case '2': return value1>value2; + case '3': return value1>=value2; + case '4': return value1 + bool checkLocal (char comp, const std::string& name, T value, const MWWorld::Ptr& actor, + const ESMS::ESMStore& store) + { + std::string scriptName = MWWorld::Class::get (actor).getScript (actor); + + if (scriptName.empty()) + return false; // no script + + const ESM::Script *script = store.scripts.find (scriptName); + + int i = 0; + + for (; i (script->varNames.size()); ++i) + if (script->varNames[i]==name) + break; + + if (i>=static_cast (script->varNames.size())) + return false; // script does not have a variable of this name + + const MWScript::Locals& locals = actor.getRefData().getLocals(); + + if (idata.numShorts) + return selectCompare (comp, locals.mShorts[i], value); + else + i -= script->data.numShorts; + + if (idata.numLongs) + return selectCompare (comp, locals.mLongs[i], value); + else + i -= script->data.numShorts; + + return selectCompare (comp, locals.mFloats.at (i), value); + } +} + namespace MWDialogue { + bool DialogueManager::isMatching (const MWWorld::Ptr& actor, + const ESM::DialInfo::SelectStruct& select) const + { + char type = select.selectRule[1]; + + if (type!='0') + { + char comp = select.selectRule[4]; + std::string name = select.selectRule.substr (5); + + // TODO types 1, 2, 4, 5, 6, 7, 8, 9, A, B, C + + switch (type) + { + case '3': // local + + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkLocal (comp, name, select.i, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkLocal (comp, name, select.f, actor, + mEnvironment.mWorld->getStore())) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + + default: + + std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; + } + } + + return true; + } + bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const { // TODO check actor id @@ -28,7 +126,11 @@ namespace MWDialogue return false; // TODO check DATAstruct - // TODO check select structures + + for (std::vector::const_iterator iter (info.selects.begin()); + iter != info.selects.end(); ++iter) + if (!isMatching (actor, *iter)) + return false; std::cout << "unchecked entries:" << std::endl @@ -39,10 +141,6 @@ namespace MWDialogue << " player faction: " << info.pcFaction << std::endl << " DATAstruct" << std::endl; - for (std::vector::const_iterator iter (info.selects.begin()); - iter != info.selects.end(); ++iter) - std::cout << " select: " << iter->selectRule << std::endl; - return true; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index d51570b11..5b6b26240 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -1,12 +1,9 @@ #ifndef GAME_MMDIALOG_DIALOGUEMANAGER_H #define GAME_MWDIALOG_DIALOGUEMANAGER_H -#include "../mwworld/ptr.hpp" +#include -namespace ESM -{ - struct DialInfo; -} +#include "../mwworld/ptr.hpp" namespace MWWorld { @@ -19,6 +16,8 @@ namespace MWDialogue { MWWorld::Environment& mEnvironment; + bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const; + bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; public: From 2acfe2297538e674f9889d77a4b0d72f46f699b3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 14:28:35 +0200 Subject: [PATCH 12/22] added test for actor ID --- apps/openmw/mwclass/creature.cpp | 8 ++++++++ apps/openmw/mwclass/creature.hpp | 3 +++ apps/openmw/mwclass/npc.cpp | 8 ++++++++ apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwdialogue/dialoguemanager.cpp | 7 +++++-- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 4 ++++ 7 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 4529094ec..1cdada64c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -10,6 +10,14 @@ namespace MWClass { + std::string Creature::getId (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->mId; + } + std::string Creature::getName (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index e964a7708..85a89a919 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -9,6 +9,9 @@ namespace MWClass { public: + virtual std::string getId (const MWWorld::Ptr& ptr) const; + ///< Return ID of \a ptr + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ae647c802..b6a4bbc05 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -10,6 +10,14 @@ namespace MWClass { + std::string Npc::getId (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->mId; + } + std::string Npc::getName (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 2ef37193a..a6f4a2965 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -9,6 +9,9 @@ namespace MWClass { public: + virtual std::string getId (const MWWorld::Ptr& ptr) const; + ///< Return ID of \a ptr + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 4f9cf602f..3c3a60180 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -114,7 +114,11 @@ namespace MWDialogue bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const { - // TODO check actor id + // actor id + if (!info.actor.empty()) + if (info.actor!=MWWorld::Class::get (actor).getId (actor)) + return false; + // TODO check actor race // TODO check actor class // TODO check actor faction @@ -134,7 +138,6 @@ namespace MWDialogue std::cout << "unchecked entries:" << std::endl - << " actor id: " << info.actor << std::endl << " actor race: " << info.race << std::endl << " actor class: " << info.clas << std::endl << " actor faction: " << info.npcFaction << std::endl diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 85e5140ea..62e0ee8c9 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -14,6 +14,11 @@ namespace MWWorld Class::~Class() {} + std::string Class::getId (const Ptr& ptr) const + { + throw std::runtime_error ("class does not support ID retrieval"); + } + MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const { throw std::runtime_error ("class does not have creature stats"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 28d96d69f..d456cc06b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -36,6 +36,10 @@ namespace MWWorld virtual ~Class(); + virtual std::string getId (const Ptr& ptr) const; + ///< Return ID of \a ptr or throw an exception, if class does not support ID retrieval + /// (default implementation: throw an exception) + virtual std::string getName (const Ptr& ptr) const = 0; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. From c7fab9aad6ae1d7231a589c9ed6b39dbb5d83112 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 14:36:45 +0200 Subject: [PATCH 13/22] added test for actor race --- apps/openmw/mwdialogue/dialoguemanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 3c3a60180..26f58dfd2 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -119,7 +119,17 @@ namespace MWDialogue if (info.actor!=MWWorld::Class::get (actor).getId (actor)) return false; - // TODO check actor race + if (!info.race.empty()) + { + ESMS::LiveCellRef *cellRef = actor.get(); + + if (!cellRef) + return false; + + if (info.race!=cellRef->base->race) + return false; + } + // TODO check actor class // TODO check actor faction // TODO check player faction @@ -138,7 +148,6 @@ namespace MWDialogue std::cout << "unchecked entries:" << std::endl - << " actor race: " << info.race << std::endl << " actor class: " << info.clas << std::endl << " actor faction: " << info.npcFaction << std::endl << " player faction: " << info.pcFaction << std::endl From fbe11956a6747e49d5f701ecdebe984384710588 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 14:43:20 +0200 Subject: [PATCH 14/22] added dummy test for select type '1' (Function); always yields false for now --- apps/openmw/mwdialogue/dialoguemanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 26f58dfd2..11a1cec08 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -82,6 +82,10 @@ namespace MWDialogue switch (type) { + case '1': // function + + return false; // TODO implement functions + case '3': // local if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || From 11bc13141741f676d8a3b94a2bb0d3a05e5fae3a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 15:09:44 +0200 Subject: [PATCH 15/22] added test for global variables --- apps/openmw/mwdialogue/dialoguemanager.cpp | 74 ++++++++++++++++++++-- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 11a1cec08..a862af06d 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -1,6 +1,10 @@ #include "dialoguemanager.hpp" +#include +#include +#include + #include #include @@ -14,6 +18,16 @@ namespace { + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } + template bool selectCompare (char comp, T1 value1, T2 value2) { @@ -64,6 +78,36 @@ namespace return selectCompare (comp, locals.mFloats.at (i), value); } + + template + bool checkGlobal (char comp, const std::string& name, T value, MWWorld::World& world) + { + switch (world.getGlobalVariableType (name)) + { + case 's': + + return selectCompare (comp, value, world.getGlobalVariable (name).mShort); + + case 'l': + + return selectCompare (comp, value, world.getGlobalVariable (name).mLong); + + case 'f': + + return selectCompare (comp, value, world.getGlobalVariable (name).mFloat); + + case ' ': + + world.getGlobalVariable (name); // trigger exception + break; + + default: + + throw std::runtime_error ("unsupported gobal variable type"); + } + + return false; + } } namespace MWDialogue @@ -78,7 +122,7 @@ namespace MWDialogue char comp = select.selectRule[4]; std::string name = select.selectRule.substr (5); - // TODO types 1, 2, 4, 5, 6, 7, 8, 9, A, B, C + // TODO types 4, 5, 6, 7, 8, 9, A, B, C switch (type) { @@ -86,18 +130,37 @@ namespace MWDialogue return false; // TODO implement functions + case '2': // global + + if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || + select.type==ESM::VT_Long) + { + if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) + return false; + } + else if (select.type==ESM::VT_Float) + { + if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) + return false; + } + else + throw std::runtime_error ( + "unsupported variable type in dialogue info select"); + + return true; + case '3': // local if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || select.type==ESM::VT_Long) { - if (!checkLocal (comp, name, select.i, actor, + if (!checkLocal (comp, toLower (name), select.i, actor, mEnvironment.mWorld->getStore())) return false; } else if (select.type==ESM::VT_Float) { - if (!checkLocal (comp, name, select.f, actor, + if (!checkLocal (comp, toLower (name), select.f, actor, mEnvironment.mWorld->getStore())) return false; } @@ -120,7 +183,7 @@ namespace MWDialogue { // actor id if (!info.actor.empty()) - if (info.actor!=MWWorld::Class::get (actor).getId (actor)) + if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) return false; if (!info.race.empty()) @@ -130,7 +193,7 @@ namespace MWDialogue if (!cellRef) return false; - if (info.race!=cellRef->base->race) + if (toLower (info.race)!=toLower (cellRef->base->race)) return false; } @@ -185,6 +248,7 @@ namespace MWDialogue if (!iter->resultScript.empty()) { + std::cout << "script: " << iter->resultScript << std::endl; // TODO execute script } From 594d3cef4f9f16318e978cb38748ac14bbd6a330 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 15:12:53 +0200 Subject: [PATCH 16/22] added test for actor class --- apps/openmw/mwdialogue/dialoguemanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index a862af06d..4f99d3a05 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -197,7 +197,17 @@ namespace MWDialogue return false; } - // TODO check actor class + if (!info.clas.empty()) + { + ESMS::LiveCellRef *cellRef = actor.get(); + + if (!cellRef) + return false; + + if (toLower (info.clas)!=toLower (cellRef->base->cls)) + return false; + } + // TODO check actor faction // TODO check player faction @@ -215,7 +225,6 @@ namespace MWDialogue std::cout << "unchecked entries:" << std::endl - << " actor class: " << info.clas << std::endl << " actor faction: " << info.npcFaction << std::endl << " player faction: " << info.pcFaction << std::endl << " DATAstruct" << std::endl; From 19c5ace6029ac2124915f030932858c1b7f039bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Aug 2010 15:17:49 +0200 Subject: [PATCH 17/22] added test for actor faction --- apps/openmw/mwdialogue/dialoguemanager.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 4f99d3a05..cbb48c6db 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -208,7 +208,17 @@ namespace MWDialogue return false; } - // TODO check actor faction + if (!info.npcFaction.empty()) + { + ESMS::LiveCellRef *cellRef = actor.get(); + + if (!cellRef) + return false; + + if (toLower (info.npcFaction)!=toLower (cellRef->base->faction)) + return false; + } + // TODO check player faction // check cell @@ -225,7 +235,6 @@ namespace MWDialogue std::cout << "unchecked entries:" << std::endl - << " actor faction: " << info.npcFaction << std::endl << " player faction: " << info.pcFaction << std::endl << " DATAstruct" << std::endl; From 181b538e4aa7088d3707af4153d4f7753c4dcfca Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Sun, 8 Aug 2010 17:20:55 +0200 Subject: [PATCH 18/22] restructured ogre nif code (struct -> class with singleton), formated code --- components/nifogre/ogre_nif_loader.cpp | 956 +++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 68 +- 2 files changed, 555 insertions(+), 469 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 670fba830..7bcecfd18 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -26,11 +26,11 @@ #include #include -#include "components/nif/nif_file.hpp" -#include "components/nif/node.hpp" -#include "components/nif/data.hpp" -#include "components/nif/property.hpp" -#include "libs/platform/strings.h" +#include "../nif/nif_file.hpp" +#include "../nif/node.hpp" +#include "../nif/data.hpp" +#include "../nif/property.hpp" +#include // For warning messages #include @@ -45,93 +45,111 @@ using namespace Ogre; using namespace Nif; using namespace Mangle::VFS; -// This is the interface to the Ogre resource system. It allows us to -// load NIFs from BSAs, in the file system and in any other place we -// tell Ogre to look (eg. in zip or rar files.) It's also used to -// check for the existence of texture files, so we can exchange the -// extension from .tga to .dds if the texture is missing. -static OgreVFS *vfs; +NIFLoader& NIFLoader::getSingleton() +{ + static NIFLoader instance; + + return instance; +} -// Singleton instance used by load() -static NIFLoader g_sing; +NIFLoader* NIFLoader::getSingletonPtr() +{ + return &getSingleton(); +} + +void NIFLoader::warn(string msg) +{ + std::cerr << "NIFLoader: Warn:" << msg << "\n"; +} -// Makeshift error reporting system -static string errName; -static void warn(const string &msg) +void NIFLoader::fail(string msg) { - cout << "WARNING (NIF:" << errName << "): " << msg << endl; + std::cerr << "NIFLoader: Fail: "<< msg << std::endl; + assert(1); } // Helper class that computes the bounding box and of a mesh class BoundsFinder { - struct MaxMinFinder - { - float max, min; + struct MaxMinFinder + { + float max, min; - MaxMinFinder() + MaxMinFinder() + { + min = numeric_limits::infinity(); + max = -min; + } + + void add(float f) + { + if (f > max) max = f; + if (f < min) min = f; + } + + // Return Max(max**2, min**2) + float getMaxSquared() + { + float m1 = max*max; + float m2 = min*min; + if (m1 >= m2) return m1; + return m2; + } + }; + + MaxMinFinder X, Y, Z; + +public: + // Add 'verts' vertices to the calculation. The 'data' pointer is + // expected to point to 3*verts floats representing x,y,z for each + // point. + void add(float *data, int verts) { - min = numeric_limits::infinity(); - max = -min; + for (int i=0;i max) max = f; - if(f < min) min = f; + return + minX() <= maxX() && + minY() <= maxY() && + minZ() <= maxZ(); } - // Return Max(max**2, min**2) - float getMaxSquared() + // Compute radius + float getRadius() { - float m1 = max*max; - float m2 = min*min; - if(m1 >= m2) return m1; - return m2; - } - }; + assert(isValid()); - MaxMinFinder X, Y, Z; + // The radius is computed from the origin, not from the geometric + // center of the mesh. + return sqrt(X.getMaxSquared() + Y.getMaxSquared() + Z.getMaxSquared()); + } -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for(int i=0;i OGRE. @@ -177,7 +195,7 @@ static CompareFunction getTestMode(int mode) } */ -static void createMaterial(const String &name, +void NIFLoader::createMaterial(const String &name, const Vector &ambient, const Vector &diffuse, const Vector &specular, @@ -186,207 +204,210 @@ static void createMaterial(const String &name, float alphaFlags, float alphaTest, const String &texName) { - MaterialPtr material = MaterialManager::getSingleton().create(name, "General"); - - // This assigns the texture to this material. If the texture name is - // a file name, and this file exists (in a resource directory), it - // will automatically be loaded when needed. If not (such as for - // internal NIF textures that we might support later), we should - // already have inserted a manual loader for the texture. - if(!texName.empty()) + MaterialPtr material = MaterialManager::getSingleton().create(name, resourceGroup); + + // This assigns the texture to this material. If the texture name is + // a file name, and this file exists (in a resource directory), it + // will automatically be loaded when needed. If not (such as for + // internal NIF textures that we might support later), we should + // already have inserted a manual loader for the texture. + if (!texName.empty()) { - Pass *pass = material->getTechnique(0)->getPass(0); - /*TextureUnitState *txt =*/ pass->createTextureUnitState(texName); - - /* As of yet UNTESTED code from Chris: - pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); - pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); - pass->setDepthCheckEnabled(true); - - // Add transparency if NiAlphaProperty was present - if(alphaFlags != -1) - { - if((alphaFlags&1)) - { - pass->setDepthWriteEnabled(false); - pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), - getBlendFactor((alphaFlags>>5)&0xf)); - } - else - pass->setDepthWriteEnabled(true); - - if((alphaFlags>>9)&1) - pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), - alphaTest); - - pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); - } - else - pass->setDepthWriteEnabled(true); - */ - - // Add transparency if NiAlphaProperty was present - if(alphaFlags != -1) + Pass *pass = material->getTechnique(0)->getPass(0); + /*TextureUnitState *txt =*/ + pass->createTextureUnitState(texName); + + /* As of yet UNTESTED code from Chris: + pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); + pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); + pass->setDepthCheckEnabled(true); + + // Add transparency if NiAlphaProperty was present + if(alphaFlags != -1) + { + if((alphaFlags&1)) + { + pass->setDepthWriteEnabled(false); + pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), + getBlendFactor((alphaFlags>>5)&0xf)); + } + else + pass->setDepthWriteEnabled(true); + + if((alphaFlags>>9)&1) + pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), + alphaTest); + + pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + } + else + pass->setDepthWriteEnabled(true); + */ + + // Add transparency if NiAlphaProperty was present + if (alphaFlags != -1) { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/property.h if you need to decode - // other values. 237 basically means normal transparencly. - if(alphaFlags == 237) + // The 237 alpha flags are by far the most common. Check + // NiAlphaProperty in nif/property.h if you need to decode + // other values. 237 basically means normal transparencly. + if (alphaFlags == 237) { - // Enable transparency - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); + // Enable transparency + pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - //pass->setDepthCheckEnabled(false); - pass->setDepthWriteEnabled(false); + //pass->setDepthCheckEnabled(false); + pass->setDepthWriteEnabled(false); } - else - warn("Unhandled alpha setting for texture " + texName); + else + warn("Unhandled alpha setting for texture " + texName); } } - // Add material bells and whistles - material->setAmbient(ambient.array[0], ambient.array[1], ambient.array[2]); - material->setDiffuse(diffuse.array[0], diffuse.array[1], diffuse.array[2], alpha); - material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha); - material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); - material->setShininess(glossiness); + // Add material bells and whistles + material->setAmbient(ambient.array[0], ambient.array[1], ambient.array[2]); + material->setDiffuse(diffuse.array[0], diffuse.array[1], diffuse.array[2], alpha); + material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha); + material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); + material->setShininess(glossiness); } // Takes a name and adds a unique part to it. This is just used to // make sure that all materials are given unique names. -static String getUniqueName(const String &input) +String NIFLoader::getUniqueName(const String &input) { - static int addon = 0; - static char buf[8]; - snprintf(buf, 8, "_%d", addon++); + static int addon = 0; + static char buf[8]; + snprintf(buf, 8, "_%d", addon++); - // Don't overflow the buffer - if(addon > 999999) addon = 0; + // Don't overflow the buffer + if (addon > 999999) addon = 0; - return input + buf; + return input + buf; } // Check if the given texture name exists in the real world. If it // does not, change the string IN PLACE to say .dds instead and try // that. The texture may still not exist, but no information of value // is lost in that case. -static void findRealTexture(String &texName) +void NIFLoader::findRealTexture(String &texName) { - assert(vfs); - if(vfs->isFile(texName)) return; + assert(vfs); + if (vfs->isFile(texName)) return; - int len = texName.size(); - if(len < 4) return; + int len = texName.size(); + if (len < 4) return; - // Change texture extension to .dds - texName[len-3] = 'd'; - texName[len-2] = 'd'; - texName[len-1] = 's'; + // Change texture extension to .dds + texName[len-3] = 'd'; + texName[len-2] = 'd'; + texName[len-1] = 's'; } // Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given // mesh. -static void createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &material) +void NIFLoader::createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &material) { - NiTriShapeData *data = shape->data.getPtr(); - SubMesh *sub = mesh->createSubMesh(shape->name.toString()); - - int nextBuf = 0; - - // This function is just one long stream of Ogre-barf, but it works - // great. - - // Add vertices - int numVerts = data->vertices.length / 3; - sub->vertexData = new VertexData(); - sub->vertexData->vertexCount = numVerts; - sub->useSharedVertices = false; - VertexDeclaration *decl = sub->vertexData->vertexDeclaration; - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); - HardwareVertexBufferSharedPtr vbuf = - HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, true); - VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; - bind->setBinding(nextBuf++, vbuf); - - // Vertex normals - if(data->normals.length) + NiTriShapeData *data = shape->data.getPtr(); + SubMesh *sub = mesh->createSubMesh(shape->name.toString()); + + int nextBuf = 0; + + // This function is just one long stream of Ogre-barf, but it works + // great. + + // Add vertices + int numVerts = data->vertices.length / 3; + sub->vertexData = new VertexData(); + sub->vertexData->vertexCount = numVerts; + sub->useSharedVertices = false; + VertexDeclaration *decl = sub->vertexData->vertexDeclaration; + decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); + HardwareVertexBufferSharedPtr vbuf = + HardwareBufferManager::getSingleton().createVertexBuffer( + VertexElement::getTypeSize(VET_FLOAT3), + numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); + vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, true); + VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; + bind->setBinding(nextBuf++, vbuf); + + // Vertex normals + if (data->normals.length) { - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), data->normals.ptr, true); - bind->setBinding(nextBuf++, vbuf); + decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL); + vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( + VertexElement::getTypeSize(VET_FLOAT3), + numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); + vbuf->writeData(0, vbuf->getSizeInBytes(), data->normals.ptr, true); + bind->setBinding(nextBuf++, vbuf); } - // Vertex colors - if(data->colors.length) + // Vertex colors + if (data->colors.length) { - const float *colors = data->colors.ptr; - RenderSystem* rs = Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(numVerts); - RGBA *pColour = &colorsRGB.front(); - for(int i=0; iconvertColourValue(ColourValue(colors[0],colors[1],colors[2], - colors[3]),pColour++); - colors += 4; - } - decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_COLOUR), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true); - bind->setBinding(nextBuf++, vbuf); + const float *colors = data->colors.ptr; + RenderSystem* rs = Root::getSingleton().getRenderSystem(); + std::vector colorsRGB(numVerts); + RGBA *pColour = &colorsRGB.front(); + for (int i=0; iconvertColourValue(ColourValue(colors[0],colors[1],colors[2], + colors[3]),pColour++); + colors += 4; + } + decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE); + vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( + VertexElement::getTypeSize(VET_COLOUR), + numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); + vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true); + bind->setBinding(nextBuf++, vbuf); } - // Texture UV coordinates - if(data->uvlist.length) + // Texture UV coordinates + if (data->uvlist.length) { - decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT2), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); + decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); + vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( + VertexElement::getTypeSize(VET_FLOAT2), + numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), data->uvlist.ptr, true); - bind->setBinding(nextBuf++, vbuf); + vbuf->writeData(0, vbuf->getSizeInBytes(), data->uvlist.ptr, true); + bind->setBinding(nextBuf++, vbuf); } - // Triangle faces - int numFaces = data->triangles.length; - if(numFaces) + // Triangle faces + int numFaces = data->triangles.length; + if (numFaces) { - HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). - createIndexBuffer(HardwareIndexBuffer::IT_16BIT, - numFaces, - HardwareBuffer::HBU_STATIC_WRITE_ONLY); - ibuf->writeData(0, ibuf->getSizeInBytes(), data->triangles.ptr, true); - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = numFaces; - sub->indexData->indexStart = 0; + HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). + createIndexBuffer(HardwareIndexBuffer::IT_16BIT, + numFaces, + HardwareBuffer::HBU_STATIC_WRITE_ONLY); + ibuf->writeData(0, ibuf->getSizeInBytes(), data->triangles.ptr, true); + sub->indexData->indexBuffer = ibuf; + sub->indexData->indexCount = numFaces; + sub->indexData->indexStart = 0; } - // Set material if one was given - if(!material.empty()) sub->setMaterialName(material); + // Set material if one was given + if (!material.empty()) sub->setMaterialName(material); - /* Old commented D code. Might be useful when reimplementing - animation. - // Assign this submesh to the given bone - VertexBoneAssignment v; - v.boneIndex = ((Bone*)bone)->getHandle(); - v.weight = 1.0; + // Assign this submesh to the given bone + //TODO: Must use niskininstance! + /*if (bone) + { + VertexBoneAssignment v; + v.boneIndex = ((Bone*)bone)->getHandle(); + v.weight = 1.0; - std::cerr << "+ Assigning bone index " << v.boneIndex << "\n"; + std::cerr << "+ Assigning bone index " << v.boneIndex << "\n"; + + for(int i=0; i < numVerts; i++) + { + v.vertexIndex = i; + sub->addBoneAssignment(v); + } + }*/ - for(int i=0; i < numVerts; i++) - { - v.vertexIndex = i; - sub->addBoneAssignment(v); - } - */ } // Helper math functions. Reinventing linear algebra for the win! @@ -394,351 +415,356 @@ static void createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &material // Computes B = AxB (matrix*matrix) static void matrixMul(const Matrix &A, Matrix &B) { - for(int i=0;i<3;i++) + for (int i=0;i<3;i++) { - float a = B.v[0].array[i]; - float b = B.v[1].array[i]; - float c = B.v[2].array[i]; + float a = B.v[0].array[i]; + float b = B.v[1].array[i]; + float c = B.v[2].array[i]; - B.v[0].array[i] = a*A.v[0].array[0] + b*A.v[0].array[1] + c*A.v[0].array[2]; - B.v[1].array[i] = a*A.v[1].array[0] + b*A.v[1].array[1] + c*A.v[1].array[2]; - B.v[2].array[i] = a*A.v[2].array[0] + b*A.v[2].array[1] + c*A.v[2].array[2]; + B.v[0].array[i] = a*A.v[0].array[0] + b*A.v[0].array[1] + c*A.v[0].array[2]; + B.v[1].array[i] = a*A.v[1].array[0] + b*A.v[1].array[1] + c*A.v[1].array[2]; + B.v[2].array[i] = a*A.v[2].array[0] + b*A.v[2].array[1] + c*A.v[2].array[2]; } } // Computes C = B + AxC*scale static void vectorMulAdd(const Matrix &A, const Vector &B, float *C, float scale) { - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for(int i=0;i<3;i++) - C[i] = B.array[i] + (a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2])*scale; + // Keep the original values + float a = C[0]; + float b = C[1]; + float c = C[2]; + + // Perform matrix multiplication, scaling and addition + for (int i=0;i<3;i++) + C[i] = B.array[i] + (a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2])*scale; } // Computes B = AxB (matrix*vector) static void vectorMul(const Matrix &A, float *C) { - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for(int i=0;i<3;i++) - C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2]; + // Keep the original values + float a = C[0]; + float b = C[1]; + float c = C[2]; + + // Perform matrix multiplication, scaling and addition + for (int i=0;i<3;i++) + C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2]; } -static void handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags, BoundsFinder &bounds) +void NIFLoader::handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags, BoundsFinder &bounds) { - assert(shape != NULL); + assert(shape != NULL); - // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision + // Interpret flags + bool hidden = (flags & 0x01) != 0; // Not displayed + bool collide = (flags & 0x02) != 0; // Use mesh for collision + bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision - // Bounding box collision isn't implemented, always use mesh for now. - if(bbcollide) + // Bounding box collision isn't implemented, always use mesh for now. + if (bbcollide) { - collide = true; - bbcollide = false; + collide = true; + bbcollide = false; } - // If the object was marked "NCO" earlier, it shouldn't collide with - // anything. - if(flags & 0x800) - { collide = false; bbcollide = false; } + // If the object was marked "NCO" earlier, it shouldn't collide with + // anything. + if (flags & 0x800) + { + collide = false; + bbcollide = false; + } - if(!collide && !bbcollide && hidden) - // This mesh apparently isn't being used for anything, so don't - // bother setting it up. - return; + if (!collide && !bbcollide && hidden) + // This mesh apparently isn't being used for anything, so don't + // bother setting it up. + return; - // Material name for this submesh, if any - String material; + // Material name for this submesh, if any + String material; - // Skip the entire material phase for hidden nodes - if(!hidden) + // Skip the entire material phase for hidden nodes + if (!hidden) { - // These are set below if present - NiTexturingProperty *t = NULL; - NiMaterialProperty *m = NULL; - NiAlphaProperty *a = NULL; - - // Scan the property list for material information - PropertyList &list = shape->props; - int n = list.length(); - for(int i=0; iprops; + int n = list.length(); + for (int i=0; irecType == RC_NiTexturingProperty) - t = (NiTexturingProperty*)pr; - else if(pr->recType == RC_NiMaterialProperty) - m = (NiMaterialProperty*)pr; - else if(pr->recType == RC_NiAlphaProperty) - a = (NiAlphaProperty*)pr; + if (pr->recType == RC_NiTexturingProperty) + t = (NiTexturingProperty*)pr; + else if (pr->recType == RC_NiMaterialProperty) + m = (NiMaterialProperty*)pr; + else if (pr->recType == RC_NiAlphaProperty) + a = (NiAlphaProperty*)pr; } - // Texture - String texName; - if(t && t->textures[0].inUse) + // Texture + String texName; + if (t && t->textures[0].inUse) { - NiSourceTexture *st = t->textures[0].texture.getPtr(); - if(st->external) + NiSourceTexture *st = t->textures[0].texture.getPtr(); + if (st->external) { - SString tname = st->filename; - - /* findRealTexture checks if the file actually - exists. If it doesn't, and the name ends in .tga, it - will try replacing the extension with .dds instead - and search for that. Bethesda at some at some point - converted all their BSA textures from tga to dds for - increased load speed, but all texture file name - references were kept as .tga. - - The function replaces the name in place (that's why - we cast away the const modifier), but this is no - problem since all the nif data is stored in a local - throwaway buffer. - */ - texName = "textures\\" + tname.toString(); - findRealTexture(texName); + SString tname = st->filename; + + /* findRealTexture checks if the file actually + exists. If it doesn't, and the name ends in .tga, it + will try replacing the extension with .dds instead + and search for that. Bethesda at some at some point + converted all their BSA textures from tga to dds for + increased load speed, but all texture file name + references were kept as .tga. + + The function replaces the name in place (that's why + we cast away the const modifier), but this is no + problem since all the nif data is stored in a local + throwaway buffer. + */ + texName = "textures\\" + tname.toString(); + findRealTexture(texName); } - else warn("Found internal texture, ignoring."); + else warn("Found internal texture, ignoring."); } - // Alpha modifiers - int alphaFlags = -1; - ubyte alphaTest = 0; - if(a) + // Alpha modifiers + int alphaFlags = -1; + ubyte alphaTest = 0; + if (a) { - alphaFlags = a->flags; - alphaTest = a->data->threshold; + alphaFlags = a->flags; + alphaTest = a->data->threshold; } - // Material - if(m || !texName.empty()) + // Material + if (m || !texName.empty()) { - // If we're here, then this mesh has a material. Thus we - // need to calculate a snappy material name. It should - // contain the mesh name (mesh->getName()) but also has to - // be unique. One mesh may use many materials. - material = getUniqueName(mesh->getName()); + // If we're here, then this mesh has a material. Thus we + // need to calculate a snappy material name. It should + // contain the mesh name (mesh->getName()) but also has to + // be unique. One mesh may use many materials. + material = getUniqueName(mesh->getName()); - if(m) + if (m) { - // Use NiMaterialProperty data to create the data - const S_MaterialProperty *d = m->data; - createMaterial(material, d->ambient, d->diffuse, d->specular, d->emissive, - d->glossiness, d->alpha, alphaFlags, alphaTest, texName); + // Use NiMaterialProperty data to create the data + const S_MaterialProperty *d = m->data; + createMaterial(material, d->ambient, d->diffuse, d->specular, d->emissive, + d->glossiness, d->alpha, alphaFlags, alphaTest, texName); } - else + else { - // We only have a texture name. Create a default - // material for it. - Vector zero, one; - for(int i=0; i<3;i++) + // We only have a texture name. Create a default + // material for it. + Vector zero, one; + for (int i=0; i<3;i++) { - zero.array[i] = 0.0; - one.array[i] = 1.0; + zero.array[i] = 0.0; + one.array[i] = 1.0; } - createMaterial(material, one, one, zero, zero, 0.0, 1.0, - alphaFlags, alphaTest, texName); + createMaterial(material, one, one, zero, zero, 0.0, 1.0, + alphaFlags, alphaTest, texName); } } } // End of material block, if(!hidden) ... - /* Do in-place transformation of all the vertices and normals. This - is pretty messy stuff, but we need it to make the sub-meshes - appear in the correct place. Neither Ogre nor Bullet support - nested levels of sub-meshes with transformations applied to each - level. - */ - NiTriShapeData *data = shape->data.getPtr(); - int numVerts = data->vertices.length / 3; - - float *ptr = (float*)data->vertices.ptr; - float *optr = ptr; - - // Rotate, scale and translate all the vertices - const Matrix &rot = shape->trafo->rotation; - const Vector &pos = shape->trafo->pos; - float scale = shape->trafo->scale; - for(int i=0; idata.getPtr(); + int numVerts = data->vertices.length / 3; + + float *ptr = (float*)data->vertices.ptr; + float *optr = ptr; + + // Rotate, scale and translate all the vertices + const Matrix &rot = shape->trafo->rotation; + const Vector &pos = shape->trafo->pos; + float scale = shape->trafo->scale; + for (int i=0; inormals.length) + // Remember to rotate all the vertex normals as well + if (data->normals.length) { - ptr = (float*)data->normals.ptr; - for(int i=0; inormals.ptr; + for (int i=0; iflags; + // Accumulate the flags from all the child nodes. This works for all + // the flags we currently use, at least. + flags |= node->flags; - // Check for extra data - Extra *e = node; - while(!e->extra.empty()) + // Check for extra data + Extra *e = node; + while (!e->extra.empty()) { - // Get the next extra data in the list - e = e->extra.getPtr(); - assert(e != NULL); + // Get the next extra data in the list + e = e->extra.getPtr(); + assert(e != NULL); - if(e->recType == RC_NiStringExtraData) + if (e->recType == RC_NiStringExtraData) { - // String markers may contain important information - // affecting the entire subtree of this node - NiStringExtraData *sd = (NiStringExtraData*)e; - - if(sd->string == "NCO") - // No collision. Use an internal flag setting to mark this. - flags |= 0x800; - else if(sd->string == "MRK") - // Marker objects. These are only visible in the - // editor. Until and unless we add an editor component to - // the engine, just skip this entire node. - return; + // String markers may contain important information + // affecting the entire subtree of this node + NiStringExtraData *sd = (NiStringExtraData*)e; + + if (sd->string == "NCO") + // No collision. Use an internal flag setting to mark this. + flags |= 0x800; + else if (sd->string == "MRK") + // Marker objects. These are only visible in the + // editor. Until and unless we add an editor component to + // the engine, just skip this entire node. + return; } } - // Apply the parent transformation to this node. We overwrite the - // existing data with the final transformation. - if(trafo) + // Apply the parent transformation to this node. We overwrite the + // existing data with the final transformation. + if (trafo) { - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - Transformation &final = *((Transformation*)node->trafo); + // Get a non-const reference to the node's data, since we're + // overwriting it. TODO: Is this necessary? + Transformation &final = *((Transformation*)node->trafo); - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - vectorMulAdd(trafo->rotation, trafo->pos, final.pos.array, trafo->scale); - vectorMulAdd(trafo->rotation, trafo->velocity, final.velocity.array, trafo->scale); + // For both position and rotation we have that: + // final_vector = old_vector + old_rotation*new_vector*old_scale + vectorMulAdd(trafo->rotation, trafo->pos, final.pos.array, trafo->scale); + vectorMulAdd(trafo->rotation, trafo->velocity, final.velocity.array, trafo->scale); - // Merge the rotations together - matrixMul(trafo->rotation, final.rotation); + // Merge the rotations together + matrixMul(trafo->rotation, final.rotation); - // Scalar values are so nice to deal with. Why can't everything - // just be scalar? - final.scale *= trafo->scale; + // Scalar values are so nice to deal with. Why can't everything + // just be scalar? + final.scale *= trafo->scale; } - // For NiNodes, loop through children - if(node->recType == RC_NiNode) + // For NiNodes, loop through children + if (node->recType == RC_NiNode) { - NodeList &list = ((NiNode*)node)->children; - int n = list.length(); - for(int i=0; ichildren; + int n = list.length(); + for (int i=0; itrafo, bounds); + if (list.has(i)) + handleNode(mesh, &list[i], flags, node->trafo, bounds); } } - else if(node->recType == RC_NiTriShape) + else if (node->recType == RC_NiTriShape) // For shapes - handleNiTriShape(mesh, dynamic_cast(node), flags, bounds); + handleNiTriShape(mesh, dynamic_cast(node), flags, bounds); } void NIFLoader::loadResource(Resource *resource) { - // Set up the VFS if it hasn't been done already - if(!vfs) vfs = new OgreVFS("General"); + // Set up the VFS if it hasn't been done already + if (!vfs) vfs = new OgreVFS(resourceGroup); + + // Get the mesh + Mesh *mesh = dynamic_cast(resource); + assert(mesh); - // Get the mesh - Mesh *mesh = dynamic_cast(resource); - assert(mesh); + // Look it up + const String &name = mesh->getName(); - // Look it up - const String &name = mesh->getName(); - errName = name; // Set name for error messages - if(!vfs->isFile(name)) + if (!vfs->isFile(name)) { - warn("File not found."); - return; + warn("File not found."); + return; } - // Helper that computes bounding boxes for us. - BoundsFinder bounds; + // Helper that computes bounding boxes for us. + BoundsFinder bounds; - // Load the NIF. TODO: Wrap this in a try-catch block once we're out - // of the early stages of development. Right now we WANT to catch - // every error as early and intrusively as possible, as it's most - // likely a sign of incomplete code rather than faulty input. - NIFFile nif(vfs->open(name), name); + // Load the NIF. TODO: Wrap this in a try-catch block once we're out + // of the early stages of development. Right now we WANT to catch + // every error as early and intrusively as possible, as it's most + // likely a sign of incomplete code rather than faulty input. + NIFFile nif(vfs->open(name), name); - if(nif.numRecords() < 1) + if (nif.numRecords() < 1) { - warn("Found no records in NIF."); - return; + warn("Found no records in NIF."); + return; } - // The first record is assumed to be the root node - Record *r = nif.getRecord(0); - assert(r != NULL); + // The first record is assumed to be the root node + Record *r = nif.getRecord(0); + assert(r != NULL); - Nif::Node *node = dynamic_cast(r); + Nif::Node *node = dynamic_cast(r); - if(node == NULL) + if (node == NULL) { - warn("First record in file was not a node, but a " + - r->recName.toString() + ". Skipping file."); - return; + warn("First record in file was not a node, but a " + + r->recName.toString() + ". Skipping file."); + return; } - // Handle the node - handleNode(mesh, node, 0, NULL, bounds); + // Handle the node + handleNode(mesh, node, 0, NULL, bounds); - // Finally, set the bounding value. - if(bounds.isValid()) + // Finally, set the bounding value. + if (bounds.isValid()) { - mesh->_setBounds(AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), - bounds.maxX(), bounds.maxY(), bounds.maxZ())); - mesh->_setBoundingSphereRadius(bounds.getRadius()); + mesh->_setBounds(AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), + bounds.maxX(), bounds.maxY(), bounds.maxZ())); + mesh->_setBoundingSphereRadius(bounds.getRadius()); } } MeshPtr NIFLoader::load(const std::string &name, const std::string &group) { - MeshManager *m = MeshManager::getSingletonPtr(); + MeshManager *m = MeshManager::getSingletonPtr(); - // Check if the resource already exists - ResourcePtr ptr = m->getByName(name, group); - if(!ptr.isNull()) - return MeshPtr(ptr); + // Check if the resource already exists + ResourcePtr ptr = m->getByName(name, group); + if (!ptr.isNull()) + return MeshPtr(ptr); - // Nope, create a new one. - return MeshManager::getSingleton().createManual(name, group, &g_sing); + // Nope, create a new one. + return MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr()); } /* More code currently not in use, from the old D source. This was diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 96b746e16..9e737779b 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -27,6 +27,26 @@ #include #include #include +#include + + +class BoundsFinder; + +namespace Nif +{ + class Node; + class Transformation; + class NiTriShape; + class Vector; +} + +namespace Mangle +{ + namespace VFS + { + class OgreVFS; + } +} /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into @@ -43,12 +63,52 @@ very resource intensive, and can safely be done for a large number of meshes at load time. */ -struct NIFLoader : Ogre::ManualResourceLoader +class NIFLoader : Ogre::ManualResourceLoader { - void loadResource(Ogre::Resource *resource); + public: + static NIFLoader& getSingleton(); + static NIFLoader* getSingletonPtr(); + + virtual void loadResource(Ogre::Resource *resource); + + static Ogre::MeshPtr load(const std::string &name, + const std::string &group="General"); + + private: + NIFLoader() : resourceGroup("General") {} + NIFLoader(NIFLoader& n) {} + + void warn(std::string msg); + void fail(std::string msg); + + void handleNode(Ogre::Mesh* mesh, Nif::Node *node, int flags, + const Nif::Transformation *trafo, BoundsFinder &bounds); + + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape, int flags, BoundsFinder &bounds); + + void createOgreMesh(Ogre::Mesh *mesh, Nif::NiTriShape *shape, const Ogre::String &material); + + void createMaterial(const Ogre::String &name, + const Nif::Vector &ambient, + const Nif::Vector &diffuse, + const Nif::Vector &specular, + const Nif::Vector &emissive, + float glossiness, float alpha, + float alphaFlags, float alphaTest, + const Ogre::String &texName); + + void findRealTexture(Ogre::String &texName); + + Ogre::String getUniqueName(const Ogre::String &input); + + // This is the interface to the Ogre resource system. It allows us to + // load NIFs from BSAs, in the file system and in any other place we + // tell Ogre to look (eg. in zip or rar files.) It's also used to + // check for the existence of texture files, so we can exchange the + // extension from .tga to .dds if the texture is missing. + Mangle::VFS::OgreVFS *vfs; - static Ogre::MeshPtr load(const std::string &name, - const std::string &group="General"); + std::string resourceGroup; }; #endif From d8f8bd12d3a5822379fec3d33aac1fa5e06d3964 Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Mon, 16 Aug 2010 19:31:59 +0200 Subject: [PATCH 19/22] Disabled loading skins.nif. NifLoader builds now a skeleton (if available) --- apps/openmw/mwrender/cellimp.cpp | 3 - components/nifogre/ogre_nif_loader.cpp | 114 +++++++++++++++++++------ components/nifogre/ogre_nif_loader.hpp | 23 ++++- 3 files changed, 107 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/cellimp.cpp b/apps/openmw/mwrender/cellimp.cpp index 121f17383..802d49385 100644 --- a/apps/openmw/mwrender/cellimp.cpp +++ b/apps/openmw/mwrender/cellimp.cpp @@ -52,9 +52,6 @@ void insertObj(CellRenderImp& cellRender, ESMS::LiveCellRefmodel); - liveRef.mData.setHandle (cellRender.insertEnd (liveRef.mData.isEnabled())); } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 7bcecfd18..4d4c1eafe 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -68,6 +68,22 @@ void NIFLoader::fail(string msg) assert(1); } +Vector3 NIFLoader::convertVector3(const Nif::Vector& vec) +{ + return Ogre::Vector3(vec.array); +} + +Quaternion NIFLoader::convertRotation(const Nif::Matrix& rot) +{ + Real matrix[3][3]; + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + matrix[i][j] = rot.v[i].array[j]; + + return Quaternion(Matrix3(matrix)); +} + // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -305,7 +321,7 @@ void NIFLoader::findRealTexture(String &texName) // Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given // mesh. -void NIFLoader::createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &material) +void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material) { NiTriShapeData *data = shape->data.getPtr(); SubMesh *sub = mesh->createSubMesh(shape->name.toString()); @@ -391,22 +407,32 @@ void NIFLoader::createOgreMesh(Mesh *mesh, NiTriShape *shape, const String &mate // Set material if one was given if (!material.empty()) sub->setMaterialName(material); - // Assign this submesh to the given bone - //TODO: Must use niskininstance! - /*if (bone) - { - VertexBoneAssignment v; - v.boneIndex = ((Bone*)bone)->getHandle(); - v.weight = 1.0; - std::cerr << "+ Assigning bone index " << v.boneIndex << "\n"; + // assigning bones if skindata is not empty + if (!shape->skin.empty()) + { + NodeList *boneList = &shape->skin->bones; - for(int i=0; i < numVerts; i++) + for (int i=0; ilength(); i++) { - v.vertexIndex = i; - sub->addBoneAssignment(v); + if (boneList->has(i)) + { + Nif::Node *bone = &(*boneList)[i]; + + SkeletonPtr skel = SkeletonManager::getSingleton().getByName(getSkeletonName()); + + VertexBoneAssignment vba; + vba.boneIndex = skel->getBone(bone->name.toString())->getHandle(); + vba.weight = 1.0; + + for (unsigned int j=0; jvertexData->vertexCount; j++) //assing every vertex + { + vba.vertexIndex = j; + sub->addBoneAssignment(vba); + } + } } - }*/ + } } @@ -453,7 +479,7 @@ static void vectorMul(const Matrix &A, float *C) C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2]; } -void NIFLoader::handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags, BoundsFinder &bounds) +void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bounds) { assert(shape != NULL); @@ -620,12 +646,12 @@ void NIFLoader::handleNiTriShape(Mesh *mesh, NiTriShape *shape, int flags, Bound bounds.add(optr, numVerts); // Create the submesh - createOgreMesh(mesh, shape, material); + createOgreSubMesh(shape, material); } } -void NIFLoader::handleNode(Mesh* mesh, Nif::Node *node, int flags, - const Transformation *trafo, BoundsFinder &bounds) +void NIFLoader::handleNode(Nif::Node *node, int flags, + const Transformation *trafo, BoundsFinder &bounds, Bone *parentBone) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -656,6 +682,36 @@ void NIFLoader::handleNode(Mesh* mesh, Nif::Node *node, int flags, } } + Bone *bone = 0; + + // create skeleton or add bones + if (node->recType == RC_NiNode) + { + if (node->name == "Bip01") //root node, create a skeleton + { + skel = SkeletonManager::getSingleton().create(getSkeletonName(), resourceGroup, true); + } + + if (!skel.isNull()) //if there is a skeleton + { + bone = skel->createBone(node->name.toString()); + + if (parentBone) + parentBone->addChild(bone); + + bone->setInheritOrientation(true); + bone->setPosition(convertVector3(node->trafo->pos)); + bone->setOrientation(convertRotation(node->trafo->rotation)); + } + + //output for debuging purpose +// Ogre::Vector3 vec(node->trafo->pos.array); +// Ogre::Quaternion q = convertRotation(node->trafo->rotation); +// std::cout << node->name.toString() << ": " << vec.x << " " << vec.y << " " << vec.z << "\n"; +// std::cout << " Y: " << q.getYaw().valueDegrees() << " P: " << q.getPitch().valueDegrees() << " R: " << q.getRoll().valueDegrees() << "\n"; + + } + // Apply the parent transformation to this node. We overwrite the // existing data with the final transformation. if (trafo) @@ -680,34 +736,36 @@ void NIFLoader::handleNode(Mesh* mesh, Nif::Node *node, int flags, // For NiNodes, loop through children if (node->recType == RC_NiNode) { - - NodeList &list = ((NiNode*)node)->children; int n = list.length(); for (int i=0; itrafo, bounds); + handleNode(&list[i], flags, node->trafo, bounds, bone); } } else if (node->recType == RC_NiTriShape) // For shapes - handleNiTriShape(mesh, dynamic_cast(node), flags, bounds); + handleNiTriShape(dynamic_cast(node), flags, bounds); } void NIFLoader::loadResource(Resource *resource) { + resourceName = ""; + mesh = 0; + skel.setNull(); + // Set up the VFS if it hasn't been done already if (!vfs) vfs = new OgreVFS(resourceGroup); // Get the mesh - Mesh *mesh = dynamic_cast(resource); + mesh = dynamic_cast(resource); assert(mesh); // Look it up - const String &name = mesh->getName(); + resourceName = mesh->getName(); - if (!vfs->isFile(name)) + if (!vfs->isFile(resourceName)) { warn("File not found."); return; @@ -720,7 +778,7 @@ void NIFLoader::loadResource(Resource *resource) // of the early stages of development. Right now we WANT to catch // every error as early and intrusively as possible, as it's most // likely a sign of incomplete code rather than faulty input. - NIFFile nif(vfs->open(name), name); + NIFFile nif(vfs->open(resourceName), resourceName); if (nif.numRecords() < 1) { @@ -742,7 +800,11 @@ void NIFLoader::loadResource(Resource *resource) } // Handle the node - handleNode(mesh, node, 0, NULL, bounds); + handleNode(node, 0, NULL, bounds, 0); + + //set skeleton + if (!skel.isNull()) + mesh->setSkeletonName(getSkeletonName()); // Finally, set the bounding value. if (bounds.isValid()) diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 9e737779b..aea8d3a8d 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -38,6 +38,7 @@ namespace Nif class Transformation; class NiTriShape; class Vector; + class Matrix; } namespace Mangle @@ -74,6 +75,9 @@ class NIFLoader : Ogre::ManualResourceLoader static Ogre::MeshPtr load(const std::string &name, const std::string &group="General"); + Ogre::Vector3 convertVector3(const Nif::Vector& vec); + Ogre::Quaternion convertRotation(const Nif::Matrix& rot); + private: NIFLoader() : resourceGroup("General") {} NIFLoader(NIFLoader& n) {} @@ -81,12 +85,12 @@ class NIFLoader : Ogre::ManualResourceLoader void warn(std::string msg); void fail(std::string msg); - void handleNode(Ogre::Mesh* mesh, Nif::Node *node, int flags, - const Nif::Transformation *trafo, BoundsFinder &bounds); + void handleNode( Nif::Node *node, int flags, + const Nif::Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone); - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape, int flags, BoundsFinder &bounds); + void handleNiTriShape(Nif::NiTriShape *shape, int flags, BoundsFinder &bounds); - void createOgreMesh(Ogre::Mesh *mesh, Nif::NiTriShape *shape, const Ogre::String &material); + void createOgreSubMesh(Nif::NiTriShape *shape, const Ogre::String &material); void createMaterial(const Ogre::String &name, const Nif::Vector &ambient, @@ -100,6 +104,12 @@ class NIFLoader : Ogre::ManualResourceLoader void findRealTexture(Ogre::String &texName); Ogre::String getUniqueName(const Ogre::String &input); + + //returns the skeleton name of this mesh + std::string getSkeletonName() + { + return resourceName + ".skel"; + } // This is the interface to the Ogre resource system. It allows us to // load NIFs from BSAs, in the file system and in any other place we @@ -108,7 +118,12 @@ class NIFLoader : Ogre::ManualResourceLoader // extension from .tga to .dds if the texture is missing. Mangle::VFS::OgreVFS *vfs; + std::string resourceName; std::string resourceGroup; + + // pointer to the ogre mesh which is currently build + Ogre::Mesh *mesh; + Ogre::SkeletonPtr skel; }; #endif From 47a28fe02b5733e3b35f50a42bdc9f8dc6fc717a Mon Sep 17 00:00:00 2001 From: Armin Preiml Date: Tue, 17 Aug 2010 19:02:22 +0200 Subject: [PATCH 20/22] If nif has a skeleton vertices are placed on the right position. --- components/nifogre/ogre_nif_loader.cpp | 206 +++++++++++-------------- 1 file changed, 92 insertions(+), 114 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4d4c1eafe..b935f49f8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -32,6 +32,7 @@ #include "../nif/property.hpp" #include +#include // For warning messages #include @@ -336,13 +337,16 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material) sub->vertexData = new VertexData(); sub->vertexData->vertexCount = numVerts; sub->useSharedVertices = false; + VertexDeclaration *decl = sub->vertexData->vertexDeclaration; decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); + HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( VertexElement::getTypeSize(VET_FLOAT3), numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, true); + VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; bind->setBinding(nextBuf++, vbuf); @@ -406,34 +410,6 @@ void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material) // Set material if one was given if (!material.empty()) sub->setMaterialName(material); - - - // assigning bones if skindata is not empty - if (!shape->skin.empty()) - { - NodeList *boneList = &shape->skin->bones; - - for (int i=0; ilength(); i++) - { - if (boneList->has(i)) - { - Nif::Node *bone = &(*boneList)[i]; - - SkeletonPtr skel = SkeletonManager::getSingleton().getByName(getSkeletonName()); - - VertexBoneAssignment vba; - vba.boneIndex = skel->getBone(bone->name.toString())->getHandle(); - vba.weight = 1.0; - - for (unsigned int j=0; jvertexData->vertexCount; j++) //assing every vertex - { - vba.vertexIndex = j; - sub->addBoneAssignment(vba); - } - } - } - } - } // Helper math functions. Reinventing linear algebra for the win! @@ -619,25 +595,99 @@ void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bou float *ptr = (float*)data->vertices.ptr; float *optr = ptr; - // Rotate, scale and translate all the vertices - const Matrix &rot = shape->trafo->rotation; - const Vector &pos = shape->trafo->pos; - float scale = shape->trafo->scale; - for (int i=0; iskin.empty()) { - vectorMulAdd(rot, pos, ptr, scale); - ptr += 3; - } + // vector that stores if the position if a vertex is absolute + std::vector vertexPosAbsolut(numVerts,false); + - // Remember to rotate all the vertex normals as well - if (data->normals.length) + float *ptrNormals = (float*)data->normals.ptr; + //the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex] + //the first one contains a link to the bone, the second vertex transformation + //relative to the bone + int boneIndex = 0; + Bone *bonePtr; + Vector3 vecPos; + Quaternion vecRot; + + std::vector boneList = shape->skin->data->bones; + + /* + Iterate through the boneList which contains what vertices are linked to + the bone (it->weights array) and at what position (it->trafo) + That position is added to every vertex. + */ + for (std::vector::iterator it = boneList.begin(); + it != boneList.end(); it++) + { + //get the bone from bones array of skindata + bonePtr = skel->getBone(shape->skin->bones[boneIndex].name.toString()); + + // final_vector = old_vector + old_rotation*new_vector*old_scale + vecPos = bonePtr->_getDerivedPosition() + + bonePtr->_getDerivedOrientation() * convertVector3(it->trafo->trans); + + vecRot = bonePtr->_getDerivedOrientation() * convertRotation(it->trafo->rotation); + + for (unsigned int i=0; iweights.length; i++) + { + unsigned int verIndex = (it->weights.ptr + i)->vertex; + + //Check if the vertex is relativ, FIXME: Is there a better solution? + if (vertexPosAbsolut[verIndex] == false) + { + //apply transformation to the vertices + Vector3 absVertPos = vecPos + vecRot * Vector3(ptr + verIndex *3); + + //convert it back to float * + for (int j=0; j<3; j++) + (ptr + verIndex*3)[j] = absVertPos[j]; + + //apply rotation to the normals (not every vertex has a normal) + //FIXME: I guessed that vertex[i] = normal[i], is that true? + if (verIndex < data->normals.length) + { + Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3); + + for (int j=0; j<3; j++) + (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; + } + + + //TODO: create vbas, and give them to createOgreSubMesh + + vertexPosAbsolut[verIndex] = true; + } + } + + boneIndex++; + //it->trafo (pos, rot, scale) of the vertex + //it->weights array containt the vertices linked to the bone and the weight + } + } + else { - ptr = (float*)data->normals.ptr; + // Rotate, scale and translate all the vertices, + const Matrix &rot = shape->trafo->rotation; + const Vector &pos = shape->trafo->pos; + float scale = shape->trafo->scale; for (int i=0; inormals.length) + { + ptr = (float*)data->normals.ptr; + for (int i=0; isetPosition(convertVector3(node->trafo->pos)); bone->setOrientation(convertRotation(node->trafo->rotation)); } - - //output for debuging purpose -// Ogre::Vector3 vec(node->trafo->pos.array); -// Ogre::Quaternion q = convertRotation(node->trafo->rotation); -// std::cout << node->name.toString() << ": " << vec.x << " " << vec.y << " " << vec.z << "\n"; -// std::cout << " Y: " << q.getYaw().valueDegrees() << " P: " << q.getPitch().valueDegrees() << " R: " << q.getRoll().valueDegrees() << "\n"; - } // Apply the parent transformation to this node. We overwrite the @@ -803,8 +846,8 @@ void NIFLoader::loadResource(Resource *resource) handleNode(node, 0, NULL, bounds, 0); //set skeleton - if (!skel.isNull()) - mesh->setSkeletonName(getSkeletonName()); +// if (!skel.isNull()) +// mesh->setSkeletonName(getSkeletonName()); // Finally, set the bounding value. if (bounds.isValid()) @@ -867,70 +910,5 @@ extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, pixelBuffer->unlock(); } -// We need this later for animated meshes. -extern "C" void* ogre_setupSkeleton(char* name) -{ - SkeletonPtr skel = SkeletonManager::getSingleton().create( - name, "Closet", true); - - skel->load(); - - // Create all bones at the origin and unrotated. This is necessary - // since our submeshes each have their own model space. We must - // move the bones after creating an entity, then copy this entity. - return (void*)skel->createBone(); -} - -extern "C" void *ogre_insertBone(char* name, void* rootBone, int32_t index) -{ - return (void*) ( ((Bone*)rootBone)->createChild(index) ); -} -*/ -/* This was the D part: - - // Create a skeleton and get the root bone (index 0) - BonePtr bone = ogre_setupSkeleton(name); - - // Reset the bone index. The next bone to be created has index 1. - boneIndex = 1; - // Create a mesh and assign the skeleton to it - MeshPtr mesh = ogre_setupMesh(name); - - // Loop through the nodes, creating submeshes, materials and - // skeleton bones in the process. - handleNode(node, bone, mesh); - - // Create the "template" entity - EntityPtr entity = ogre_createEntity(name); - - // Loop through once again, this time to set the right - // transformations on the entity's SkeletonInstance. The order of - // children will be the same, allowing us to reference bones using - // their boneIndex. - int lastBone = boneIndex; - boneIndex = 1; - transformBones(node, entity); - if(lastBone != boneIndex) writefln("WARNING: Bone number doesn't match"); - - if(!hasBBox) - ogre_setMeshBoundingBox(mesh, minX, minY, minZ, maxX, maxY, maxZ); - - return entity; -} -void handleNode(Node node, BonePtr root, MeshPtr mesh) -{ - // Insert a new bone for this node - BonePtr bone = ogre_insertBone(node.name, root, boneIndex++); - -} - -void transformBones(Node node, EntityPtr entity) -{ - ogre_transformBone(entity, &node.trafo, boneIndex++); - NiNode n = cast(NiNode)node; - if(n !is null) - foreach(Node nd; n.children) - transformBones(nd, entity); -} */ From e42f1bbc11cadcd2ffe672c78ccde52e452d6bd5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 18 Aug 2010 09:19:16 +0200 Subject: [PATCH 21/22] open dialogue window, if a matching greetings info record is found --- apps/openmw/mwdialogue/dialoguemanager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index cbb48c6db..85a955992 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -14,6 +14,8 @@ #include "../mwworld/world.hpp" #include "../mwworld/refdata.hpp" +#include "../mwgui/window_manager.hpp" + #include namespace @@ -270,7 +272,7 @@ namespace MWDialogue // TODO execute script } - break; + mEnvironment.mWindowManager->setMode (MWGui::GM_Dialogue); } } } From 62586543833981c2ca396b94bbe591b5f3e56ed7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 18 Aug 2010 09:32:36 +0200 Subject: [PATCH 22/22] fixed a very sloppy merge --- apps/openmw/mwclass/npc.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index a12d939d8..3bc005b06 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -98,15 +98,12 @@ namespace MWClass return *ptr.getRefData().getCreatureStats(); } -<<<<<<< HEAD:apps/openmw/mwclass/npc.cpp -======= boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const { return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } ->>>>>>> master:apps/openmw/mwclass/npc.cpp MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr) const { @@ -121,12 +118,6 @@ namespace MWClass } return *ptr.getRefData().getContainerStore(); - } - - boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const - { - return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } std::string Npc::getScript (const MWWorld::Ptr& ptr) const