Merge branch 'next' into terrain_next
Conflicts: CMakeLists.txt apps/openmw/CMakeLists.txt apps/openmw/mwrender/renderingmanager.cpp apps/openmw/mwrender/renderingmanager.hpp cmake/FindOGRE.cmakeactorid
commit
f2c3616638
@ -1,5 +0,0 @@
|
||||
esmtool_cmd.c: esmtool.ggo
|
||||
gengetopt < esmtool.ggo
|
||||
|
||||
clean:
|
||||
rm esmtool_cmd.c esmtool_cmd.h
|
@ -1,28 +0,0 @@
|
||||
#ifndef GAME_MWCLASS_CONTAINERUTIL_H
|
||||
#define GAME_MWCLASS_CONTAINERUTIL_H
|
||||
|
||||
#include <components/esm_store/cell_store.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
|
||||
namespace MWClass
|
||||
{
|
||||
template<typename T>
|
||||
void insertIntoContainerStore (const MWWorld::Ptr& ptr,
|
||||
ESMS::CellRefList<T, MWWorld::RefData>& containerStore)
|
||||
{
|
||||
if (!ptr.isEmpty())
|
||||
{
|
||||
// TODO check stacking
|
||||
|
||||
ESMS::LiveCellRef<T, MWWorld::RefData> cellRef(ptr.getCellRef(), ptr.get<T>()->base);
|
||||
cellRef.mData = ptr.getRefData();
|
||||
|
||||
containerStore.list.push_back (cellRef);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,629 @@
|
||||
#include "charactercreation.hpp"
|
||||
|
||||
#include "text_input.hpp"
|
||||
#include "race.hpp"
|
||||
#include "class.hpp"
|
||||
#include "birth.hpp"
|
||||
#include "review.hpp"
|
||||
#include "dialogue.hpp"
|
||||
#include "mode.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Step
|
||||
{
|
||||
const char* mText;
|
||||
const char* mButtons[3];
|
||||
ESM::Class::Specialization mSpecializations[3]; // The specialization for each answer
|
||||
};
|
||||
|
||||
static boost::array<Step, 10> sGenerateClassSteps = { {
|
||||
// Question 1
|
||||
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.",
|
||||
{"Draw your dagger, mercifully endings its life with a single thrust.",
|
||||
"Use herbs from your pack to put it to sleep.",
|
||||
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 2
|
||||
{"One Summer afternoon your father gives you a choice of chores.",
|
||||
{"Work in the forge with him casting iron for a new plow.",
|
||||
"Gather herbs for your mother who is preparing dinner.",
|
||||
"Go catch fish at the stream using a net and line."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 3
|
||||
{"Your cousin has given you a very embarrassing nickname and, even worse, likes to call you it in front of your friends. You asked him to stop, but he finds it very amusing to watch you blush.",
|
||||
{"Beat up your cousin, then tell him that if he ever calls you that nickname again, you will bloody him worse than this time.",
|
||||
"Make up a story that makes your nickname a badge of honor instead of something humiliating.",
|
||||
"Make up an even more embarrassing nickname for him and use it constantly until he learns his lesson."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 4
|
||||
{"There is a lot of heated discussion at the local tavern over a grouped of people called 'Telepaths'. They have been hired by certain City-State kings. Rumor has it these Telepaths read a person's mind and tell their lord whether a follower is telling the truth or not.",
|
||||
{"This is a terrible practice. A person's thoughts are his own and no one, not even a king, has the right to make such an invasion into another human's mind.",
|
||||
"Loyal followers to the king have nothing to fear from a Telepath. It is important to have a method of finding assassins and spies before it is too late.",
|
||||
"In these times, it is a necessary evil. Although you do not necessarily like the idea, a Telepath could have certain advantages during a time of war or in finding someone innocent of a crime."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 5
|
||||
{"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.",
|
||||
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
|
||||
"Decide to put the extra money to good use and purchase items that would help your family?",
|
||||
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?"},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 6
|
||||
{"While in the market place you witness a thief cut a purse from a noble. Even as he does so, the noble notices and calls for the city guards. In his haste to get away, the thief drops the purse near you. Surprisingly no one seems to notice the bag of coins at your feet.",
|
||||
{"Pick up the bag and signal to the guard, knowing that the only honorable thing to do is return the money to its rightful owner.",
|
||||
"Leave the bag there, knowing that it is better not to get involved.",
|
||||
"Pick up the bag and pocket it, knowing that the extra windfall will help your family in times of trouble."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 7
|
||||
{"Your father sends you on a task which you loathe, cleaning the stables. On the way there, pitchfork in hand, you run into your friend from the homestead near your own. He offers to do it for you, in return for a future favor of his choosing.",
|
||||
{"Decline his offer, knowing that your father expects you to do the work, and it is better not to be in debt.",
|
||||
"Ask him to help you, knowing that two people can do the job faster than one, and agree to help him with one task of his choosing in the future.",
|
||||
"Accept his offer, reasoning that as long as the stables are cleaned, it matters not who does the cleaning."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 8
|
||||
{"Your mother asks you to help fix the stove. While you are working, a very hot pipe slips its mooring and falls towards her.",
|
||||
{"Position yourself between the pipe and your mother.",
|
||||
"Grab the hot pipe and try to push it away.",
|
||||
"Push your mother out of the way."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 9
|
||||
{"While in town the baker gives you a sweetroll. Delighted, you take it into an alley to enjoy only to be intercepted by a gang of three other kids your age. The leader demands the sweetroll, or else he and his friends will beat you and take it.",
|
||||
{"Drop the sweetroll and step on it, then get ready for the fight.",
|
||||
"Give him the sweetroll now without argument, knowing that later this afternoon you will have all your friends with you and can come and take whatever he owes you.",
|
||||
"Act like you're going to give him the sweetroll, but at the last minute throw it in the air, hoping that they'll pay attention to it long enough for you to get a shot in on the leader."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
},
|
||||
// Question 10
|
||||
{"Entering town you find that you are witness to a very well-dressed man running from a crowd. He screams to you for help. The crowd behind him seem very angry.",
|
||||
{"Rush to the town's aid immediately, despite your lack of knowledge of the circumstances.",
|
||||
"Stand aside and allow the man and the mob to pass, realizing it is probably best not to get involved.",
|
||||
"Rush to the man's aid immediately, despite your lack of knowledge of the circumstances."},
|
||||
{ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}
|
||||
}
|
||||
} };
|
||||
}
|
||||
|
||||
using namespace MWGui;
|
||||
|
||||
CharacterCreation::CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment)
|
||||
: mNameDialog(0)
|
||||
, mRaceDialog(0)
|
||||
, mDialogueWindow(0)
|
||||
, mClassChoiceDialog(0)
|
||||
, mGenerateClassQuestionDialog(0)
|
||||
, mGenerateClassResultDialog(0)
|
||||
, mPickClassDialog(0)
|
||||
, mCreateClassDialog(0)
|
||||
, mBirthSignDialog(0)
|
||||
, mReviewDialog(0)
|
||||
, mWM(_wm)
|
||||
, mEnvironment(_environment)
|
||||
{
|
||||
mCreationStage = CSE_NotStarted;
|
||||
}
|
||||
|
||||
void CharacterCreation::spawnDialog(const char id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case GM_Name:
|
||||
if(mNameDialog)
|
||||
mWM->removeDialog(mNameDialog);
|
||||
mNameDialog = new TextInputDialog(*mWM);
|
||||
mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name"));
|
||||
mNameDialog->setTextInput(mPlayerName);
|
||||
mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen);
|
||||
mNameDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone);
|
||||
mNameDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Race:
|
||||
if (mRaceDialog)
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
mRaceDialog = new RaceDialog(*mWM);
|
||||
mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen);
|
||||
mRaceDialog->setRaceId(mPlayerRaceId);
|
||||
mRaceDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone);
|
||||
mRaceDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack);
|
||||
mRaceDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Class:
|
||||
if (mClassChoiceDialog)
|
||||
mWM->removeDialog(mClassChoiceDialog);
|
||||
mClassChoiceDialog = new ClassChoiceDialog(*mWM);
|
||||
mClassChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassChoice);
|
||||
mClassChoiceDialog->open();
|
||||
break;
|
||||
|
||||
case GM_ClassPick:
|
||||
if (mPickClassDialog)
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
mPickClassDialog = new PickClassDialog(*mWM);
|
||||
mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen);
|
||||
mPickClassDialog->setClassId(mPlayerClass.name);
|
||||
mPickClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone);
|
||||
mPickClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack);
|
||||
mPickClassDialog->open();
|
||||
break;
|
||||
|
||||
case GM_Birth:
|
||||
if (mBirthSignDialog)
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
mBirthSignDialog = new BirthDialog(*mWM);
|
||||
mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen);
|
||||
mBirthSignDialog->setBirthId(mPlayerBirthSignId);
|
||||
mBirthSignDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone);
|
||||
mBirthSignDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack);
|
||||
mBirthSignDialog->open();
|
||||
break;
|
||||
|
||||
case GM_ClassCreate:
|
||||
if (mCreateClassDialog)
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
mCreateClassDialog = new CreateClassDialog(*mWM);
|
||||
mCreateClassDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone);
|
||||
mCreateClassDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack);
|
||||
mCreateClassDialog->open();
|
||||
break;
|
||||
case GM_ClassGenerate:
|
||||
mGenerateClassStep = 0;
|
||||
mGenerateClass = "";
|
||||
mGenerateClassSpecializations[0] = 0;
|
||||
mGenerateClassSpecializations[1] = 0;
|
||||
mGenerateClassSpecializations[2] = 0;
|
||||
showClassQuestionDialog();
|
||||
break;
|
||||
case GM_Review:
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
mReviewDialog = new ReviewDialog(*mWM);
|
||||
mReviewDialog->setPlayerName(mPlayerName);
|
||||
mReviewDialog->setRace(mPlayerRaceId);
|
||||
mReviewDialog->setClass(mPlayerClass);
|
||||
mReviewDialog->setBirthSign(mPlayerBirthSignId);
|
||||
|
||||
mReviewDialog->setHealth(mPlayerHealth);
|
||||
mReviewDialog->setMagicka(mPlayerMagicka);
|
||||
mReviewDialog->setFatigue(mPlayerFatigue);
|
||||
|
||||
{
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator end = mPlayerAttributes.end();
|
||||
for (std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> >::iterator it = mPlayerAttributes.begin(); it != end; ++it)
|
||||
{
|
||||
mReviewDialog->setAttribute(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator end = mPlayerSkillValues.end();
|
||||
for (std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> >::iterator it = mPlayerSkillValues.begin(); it != end; ++it)
|
||||
{
|
||||
mReviewDialog->setSkillValue(it->first, it->second);
|
||||
}
|
||||
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
|
||||
}
|
||||
|
||||
mReviewDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone);
|
||||
mReviewDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack);
|
||||
mReviewDialog->eventActivateDialog = MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog);
|
||||
mReviewDialog->open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerHealth = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerMagicka = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat<int>& value)
|
||||
{
|
||||
mPlayerFatigue = value;
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewDialogBack()
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
}
|
||||
|
||||
void CharacterCreation::onReviewActivateDialog(int parDialog)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mWM->removeDialog(mReviewDialog);
|
||||
mCreationStage = CSE_ReviewNext;
|
||||
|
||||
switch(parDialog)
|
||||
{
|
||||
case ReviewDialog::NAME_DIALOG:
|
||||
mWM->setGuiMode(GM_Name);
|
||||
break;
|
||||
case ReviewDialog::RACE_DIALOG:
|
||||
mWM->setGuiMode(GM_Race);
|
||||
break;
|
||||
case ReviewDialog::CLASS_DIALOG:
|
||||
mWM->setGuiMode(GM_Class);
|
||||
break;
|
||||
case ReviewDialog::BIRTHSIGN_DIALOG:
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
};
|
||||
}
|
||||
|
||||
void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mPickClassDialog)
|
||||
{
|
||||
const std::string &classId = mPickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(classId);
|
||||
const ESM::Class *klass = mEnvironment->mWorld->getStore().classes.find(classId);
|
||||
if (klass)
|
||||
{
|
||||
mPlayerClass = *klass;
|
||||
mWM->setPlayerClass(mPlayerClass);
|
||||
}
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
}
|
||||
|
||||
//TODO This bit gets repeated a few times; wrap it in a function
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onPickClassDialogBack()
|
||||
{
|
||||
if (mPickClassDialog)
|
||||
{
|
||||
const std::string classId = mPickClassDialog->getClassId();
|
||||
if (!classId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(classId);
|
||||
mWM->removeDialog(mPickClassDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onClassChoice(int _index)
|
||||
{
|
||||
if (mClassChoiceDialog)
|
||||
{
|
||||
mWM->removeDialog(mClassChoiceDialog);
|
||||
}
|
||||
|
||||
switch(_index)
|
||||
{
|
||||
case ClassChoiceDialog::Class_Generate:
|
||||
mWM->setGuiMode(GM_ClassGenerate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Pick:
|
||||
mWM->setGuiMode(GM_ClassPick);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Create:
|
||||
mWM->setGuiMode(GM_ClassCreate);
|
||||
break;
|
||||
case ClassChoiceDialog::Class_Back:
|
||||
mWM->setGuiMode(GM_Race);
|
||||
break;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
void CharacterCreation::onNameDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mNameDialog)
|
||||
{
|
||||
mPlayerName = mNameDialog->getTextInput();
|
||||
mWM->setValue("name", mPlayerName);
|
||||
mEnvironment->mMechanicsManager->setPlayerName(mPlayerName);
|
||||
mWM->removeDialog(mNameDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_NameChosen)
|
||||
mWM->setGuiMode(GM_Race);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_NameChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onRaceDialogBack()
|
||||
{
|
||||
if (mRaceDialog)
|
||||
{
|
||||
mPlayerRaceId = mRaceDialog->getRaceId();
|
||||
if (!mPlayerRaceId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male);
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Name);
|
||||
}
|
||||
|
||||
void CharacterCreation::onRaceDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mRaceDialog)
|
||||
{
|
||||
mPlayerRaceId = mRaceDialog->getRaceId();
|
||||
mWM->setValue("race", mPlayerRaceId);
|
||||
if (!mPlayerRaceId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male);
|
||||
mWM->removeDialog(mRaceDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if(mCreationStage >= CSE_RaceChosen)
|
||||
mWM->setGuiMode(GM_Class);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_RaceChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mBirthSignDialog)
|
||||
{
|
||||
mPlayerBirthSignId = mBirthSignDialog->getBirthId();
|
||||
mWM->setBirthSign(mPlayerBirthSignId);
|
||||
if (!mPlayerBirthSignId.empty())
|
||||
mEnvironment->mMechanicsManager->setPlayerBirthsign(mPlayerBirthSignId);
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage >= CSE_BirthSignChosen)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_BirthSignChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onBirthSignDialogBack()
|
||||
{
|
||||
if (mBirthSignDialog)
|
||||
{
|
||||
mEnvironment->mMechanicsManager->setPlayerBirthsign(mBirthSignDialog->getBirthId());
|
||||
mWM->removeDialog(mBirthSignDialog);
|
||||
}
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mCreateClassDialog)
|
||||
{
|
||||
ESM::Class klass;
|
||||
klass.name = mCreateClassDialog->getName();
|
||||
klass.description = mCreateClassDialog->getDescription();
|
||||
klass.data.specialization = mCreateClassDialog->getSpecializationId();
|
||||
klass.data.isPlayable = 0x1;
|
||||
|
||||
std::vector<int> attributes = mCreateClassDialog->getFavoriteAttributes();
|
||||
assert(attributes.size() == 2);
|
||||
klass.data.attribute[0] = attributes[0];
|
||||
klass.data.attribute[1] = attributes[1];
|
||||
|
||||
std::vector<ESM::Skill::SkillEnum> majorSkills = mCreateClassDialog->getMajorSkills();
|
||||
std::vector<ESM::Skill::SkillEnum> minorSkills = mCreateClassDialog->getMinorSkills();
|
||||
assert(majorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
assert(minorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
|
||||
for (size_t i = 0; i < sizeof(klass.data.skills)/sizeof(klass.data.skills[0]); ++i)
|
||||
{
|
||||
klass.data.skills[i][1] = majorSkills[i];
|
||||
klass.data.skills[i][0] = minorSkills[i];
|
||||
}
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(klass);
|
||||
mPlayerClass = klass;
|
||||
mWM->setPlayerClass(klass);
|
||||
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
}
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterCreation::onCreateClassDialogBack()
|
||||
{
|
||||
if (mCreateClassDialog)
|
||||
mWM->removeDialog(mCreateClassDialog);
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onClassQuestionChosen(int _index)
|
||||
{
|
||||
if (mGenerateClassQuestionDialog)
|
||||
mWM->removeDialog(mGenerateClassQuestionDialog);
|
||||
if (_index < 0 || _index >= 3)
|
||||
{
|
||||
mWM->setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
ESM::Class::Specialization specialization = sGenerateClassSteps[mGenerateClassStep].mSpecializations[_index];
|
||||
if (specialization == ESM::Class::Stealth)
|
||||
++mGenerateClassSpecializations[0];
|
||||
else if (specialization == ESM::Class::Combat)
|
||||
++mGenerateClassSpecializations[1];
|
||||
else if (specialization == ESM::Class::Magic)
|
||||
++mGenerateClassSpecializations[2];
|
||||
++mGenerateClassStep;
|
||||
showClassQuestionDialog();
|
||||
}
|
||||
|
||||
void CharacterCreation::showClassQuestionDialog()
|
||||
{
|
||||
if (mGenerateClassStep == sGenerateClassSteps.size())
|
||||
{
|
||||
static boost::array<ClassPoint, 23> classes = { {
|
||||
{"Acrobat", {6, 2, 2}},
|
||||
{"Agent", {6, 1, 3}},
|
||||
{"Archer", {3, 5, 2}},
|
||||
{"Archer", {5, 5, 0}},
|
||||
{"Assassin", {6, 3, 1}},
|
||||
{"Barbarian", {3, 6, 1}},
|
||||
{"Bard", {3, 3, 3}},
|
||||
{"Battlemage", {1, 3, 6}},
|
||||
{"Crusader", {1, 6, 3}},
|
||||
{"Healer", {3, 1, 6}},
|
||||
{"Knight", {2, 6, 2}},
|
||||
{"Monk", {5, 3, 2}},
|
||||
{"Nightblade", {4, 2, 4}},
|
||||
{"Pilgrim", {5, 2, 3}},
|
||||
{"Rogue", {3, 4, 3}},
|
||||
{"Rogue", {4, 4, 2}},
|
||||
{"Rogue", {5, 4, 1}},
|
||||
{"Scout", {2, 5, 3}},
|
||||
{"Sorcerer", {2, 2, 6}},
|
||||
{"Spellsword", {2, 4, 4}},
|
||||
{"Spellsword", {5, 1, 4}},
|
||||
{"Witchhunter", {2, 3, 5}},
|
||||
{"Witchhunter", {5, 0, 5}}
|
||||
} };
|
||||
|
||||
int match = -1;
|
||||
for (unsigned i = 0; i < classes.size(); ++i)
|
||||
{
|
||||
if (mGenerateClassSpecializations[0] == classes[i].points[0] &&
|
||||
mGenerateClassSpecializations[1] == classes[i].points[1] &&
|
||||
mGenerateClassSpecializations[2] == classes[i].points[2])
|
||||
{
|
||||
match = i;
|
||||
mGenerateClass = classes[i].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match == -1)
|
||||
{
|
||||
if (mGenerateClassSpecializations[0] >= 7)
|
||||
mGenerateClass = "Thief";
|
||||
else if (mGenerateClassSpecializations[1] >= 7)
|
||||
mGenerateClass = "Warrior";
|
||||
else if (mGenerateClassSpecializations[2] >= 7)
|
||||
mGenerateClass = "Mage";
|
||||
else
|
||||
{
|
||||
std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl;
|
||||
mGenerateClass = "Thief";
|
||||
}
|
||||
}
|
||||
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM);
|
||||
mGenerateClassResultDialog->setClassId(mGenerateClass);
|
||||
mGenerateClassResultDialog->eventBack = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack);
|
||||
mGenerateClassResultDialog->eventDone = MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone);
|
||||
mGenerateClassResultDialog->open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGenerateClassStep > sGenerateClassSteps.size())
|
||||
{
|
||||
mWM->setGuiMode(GM_Class);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mGenerateClassQuestionDialog)
|
||||
mWM->removeDialog(mGenerateClassQuestionDialog);
|
||||
mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM);
|
||||
|
||||
InfoBoxDialog::ButtonList buttons;
|
||||
mGenerateClassQuestionDialog->setText(sGenerateClassSteps[mGenerateClassStep].mText);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[0]);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[1]);
|
||||
buttons.push_back(sGenerateClassSteps[mGenerateClassStep].mButtons[2]);
|
||||
mGenerateClassQuestionDialog->setButtons(buttons);
|
||||
mGenerateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
|
||||
mGenerateClassQuestionDialog->open();
|
||||
}
|
||||
|
||||
void CharacterCreation::onGenerateClassBack()
|
||||
{
|
||||
if(mCreationStage < CSE_ClassChosen)
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass);
|
||||
|
||||
mWM->setGuiMode(GM_Class);
|
||||
}
|
||||
|
||||
void CharacterCreation::onGenerateClassDone(WindowBase* parWindow)
|
||||
{
|
||||
if (mGenerateClassResultDialog)
|
||||
mWM->removeDialog(mGenerateClassResultDialog);
|
||||
mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass);
|
||||
|
||||
if (mCreationStage == CSE_ReviewNext)
|
||||
mWM->setGuiMode(GM_Review);
|
||||
else if (mCreationStage >= CSE_ClassChosen)
|
||||
mWM->setGuiMode(GM_Birth);
|
||||
else
|
||||
{
|
||||
mCreationStage = CSE_ClassChosen;
|
||||
mWM->setGuiMode(GM_Game);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterCreation::~CharacterCreation()
|
||||
{
|
||||
delete mNameDialog;
|
||||
delete mRaceDialog;
|
||||
delete mDialogueWindow;
|
||||
delete mClassChoiceDialog;
|
||||
delete mGenerateClassQuestionDialog;
|
||||
delete mGenerateClassResultDialog;
|
||||
delete mPickClassDialog;
|
||||
delete mCreateClassDialog;
|
||||
delete mBirthSignDialog;
|
||||
delete mReviewDialog;
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
#ifndef CHARACTER_CREATION_HPP
|
||||
#define CHARACTER_CREATION_HPP
|
||||
|
||||
#include "window_manager.hpp"
|
||||
|
||||
#include "../mwmechanics/mechanicsmanager.hpp"
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
class WindowBase;
|
||||
|
||||
class TextInputDialog;
|
||||
class InfoBoxDialog;
|
||||
class RaceDialog;
|
||||
class DialogueWindow;
|
||||
class ClassChoiceDialog;
|
||||
class GenerateClassResultDialog;
|
||||
class PickClassDialog;
|
||||
class CreateClassDialog;
|
||||
class BirthDialog;
|
||||
class ReviewDialog;
|
||||
class MessageBoxManager;
|
||||
|
||||
class CharacterCreation
|
||||
{
|
||||
public:
|
||||
typedef std::vector<int> SkillList;
|
||||
|
||||
CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment);
|
||||
~CharacterCreation();
|
||||
|
||||
//Show a dialog
|
||||
void spawnDialog(const char id);
|
||||
|
||||
void setPlayerHealth (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
void setPlayerMagicka (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
void setPlayerFatigue (const MWMechanics::DynamicStat<int>& value);
|
||||
|
||||
private:
|
||||
//Dialogs
|
||||
TextInputDialog* mNameDialog;
|
||||
RaceDialog* mRaceDialog;
|
||||
DialogueWindow* mDialogueWindow;
|
||||
ClassChoiceDialog* mClassChoiceDialog;
|
||||
InfoBoxDialog* mGenerateClassQuestionDialog;
|
||||
GenerateClassResultDialog* mGenerateClassResultDialog;
|
||||
PickClassDialog* mPickClassDialog;
|
||||
CreateClassDialog* mCreateClassDialog;
|
||||
BirthDialog* mBirthSignDialog;
|
||||
ReviewDialog* mReviewDialog;
|
||||
|
||||
WindowManager* mWM;
|
||||
MWWorld::Environment* mEnvironment;
|
||||
|
||||
//Player data
|
||||
std::string mPlayerName;
|
||||
std::string mPlayerRaceId;
|
||||
std::string mPlayerBirthSignId;
|
||||
ESM::Class mPlayerClass;
|
||||
std::map<ESM::Attribute::AttributeID, MWMechanics::Stat<int> > mPlayerAttributes;
|
||||
SkillList mPlayerMajorSkills, mPlayerMinorSkills;
|
||||
std::map<ESM::Skill::SkillEnum, MWMechanics::Stat<float> > mPlayerSkillValues;
|
||||
MWMechanics::DynamicStat<int> mPlayerHealth;
|
||||
MWMechanics::DynamicStat<int> mPlayerMagicka;
|
||||
MWMechanics::DynamicStat<int> mPlayerFatigue;
|
||||
|
||||
//Class generation vars
|
||||
unsigned mGenerateClassStep; // Keeps track of current step in Generate Class dialog
|
||||
unsigned mGenerateClassSpecializations[3]; // A counter for each specialization which is increased when an answer is chosen
|
||||
std::string mGenerateClass; // In order: Stealth, Combat, Magic
|
||||
|
||||
////Dialog events
|
||||
//Name dialog
|
||||
void onNameDialogDone(WindowBase* parWindow);
|
||||
|
||||
//Race dialog
|
||||
void onRaceDialogDone(WindowBase* parWindow);
|
||||
void onRaceDialogBack();
|
||||
|
||||
//Class dialogs
|
||||
void onClassChoice(int _index);
|
||||
void onPickClassDialogDone(WindowBase* parWindow);
|
||||
void onPickClassDialogBack();
|
||||
void onCreateClassDialogDone(WindowBase* parWindow);
|
||||
void onCreateClassDialogBack();
|
||||
void showClassQuestionDialog();
|
||||
void onClassQuestionChosen(int _index);
|
||||
void onGenerateClassBack();
|
||||
void onGenerateClassDone(WindowBase* parWindow);
|
||||
|
||||
//Birthsign dialog
|
||||
void onBirthSignDialogDone(WindowBase* parWindow);
|
||||
void onBirthSignDialogBack();
|
||||
|
||||
//Review dialog
|
||||
void onReviewDialogDone(WindowBase* parWindow);
|
||||
void onReviewDialogBack();
|
||||
void onReviewActivateDialog(int parDialog);
|
||||
|
||||
enum CSE //Creation Stage Enum
|
||||
{
|
||||
CSE_NotStarted,
|
||||
CSE_NameChosen,
|
||||
CSE_RaceChosen,
|
||||
CSE_ClassChosen,
|
||||
CSE_BirthSignChosen,
|
||||
CSE_ReviewNext
|
||||
};
|
||||
|
||||
CSE mCreationStage; // Which state the character creating is in, controls back/next/ok buttons
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,193 @@
|
||||
#include "journalwindow.hpp"
|
||||
#include "window_manager.hpp"
|
||||
#include "../mwdialogue/journal.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct book
|
||||
{
|
||||
int endLine;
|
||||
std::list<std::string> pages;
|
||||
};
|
||||
}
|
||||
|
||||
book formatText(std::string text,book mBook,int maxLine, int lineSize)
|
||||
{
|
||||
//stringList.push_back("");
|
||||
|
||||
int cLineSize = 0;
|
||||
int cLine = mBook.endLine +1;
|
||||
std::string cString;
|
||||
|
||||
if(mBook.pages.empty())
|
||||
{
|
||||
cString = "";
|
||||
cLine = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cString = mBook.pages.back() + std::string("\n");
|
||||
mBook.pages.pop_back();
|
||||
}
|
||||
|
||||
//std::string::iterator wordBegin = text.begin();
|
||||
//std::string::iterator wordEnd;
|
||||
|
||||
std::string cText = text;
|
||||
|
||||
while(cText.length() != 0)
|
||||
{
|
||||
size_t firstSpace = cText.find_first_of(' ');
|
||||
if(firstSpace == std::string::npos)
|
||||
{
|
||||
cString = cString + cText;
|
||||
mBook.pages.push_back(cString);
|
||||
//TODO:finnish this
|
||||
break;
|
||||
}
|
||||
if(static_cast<int> (firstSpace) + cLineSize <= lineSize)
|
||||
{
|
||||
cLineSize = firstSpace + cLineSize;
|
||||
cString = cString + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLineSize = firstSpace;
|
||||
if(cLine +1 <= maxLine)
|
||||
{
|
||||
cLine = cLine + 1;
|
||||
cString = cString + std::string("\n") + cText.substr(0,firstSpace +1);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLine = 0;
|
||||
mBook.pages.push_back(cString);
|
||||
cString = cText.substr(0,firstSpace +1);
|
||||
}
|
||||
}
|
||||
//std::cout << cText << "\n";
|
||||
//std::cout << cText.length();
|
||||
cText = cText.substr(firstSpace +1,cText.length() - firstSpace -1);
|
||||
}
|
||||
mBook.endLine = cLine;
|
||||
return mBook;
|
||||
//std::string
|
||||
}
|
||||
|
||||
|
||||
MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager)
|
||||
: WindowBase("openmw_journal_layout.xml", parWindowManager)
|
||||
, lastPos(0)
|
||||
{
|
||||
//setCoord(0,0,498, 342);
|
||||
center();
|
||||
|
||||
getWidget(mLeftTextWidget, "LeftText");
|
||||
getWidget(mRightTextWidget, "RightText");
|
||||
getWidget(mPrevBtn, "PrevPageBTN");
|
||||
mPrevBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage);
|
||||
getWidget(mNextBtn, "NextPageBTN");
|
||||
mNextBtn->eventMouseButtonClick = MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage);
|
||||
//MyGUI::ItemBox* list = new MyGUI::ItemBox();
|
||||
//list->addItem("qaq","aqzazaz");
|
||||
//mScrollerWidget->addChildItem(list);
|
||||
//mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg"));
|
||||
//mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvl<kbvlqksbgkqsjhdvb");
|
||||
//mEditWidget->show();
|
||||
//mEditWidget->setEditStatic(true);
|
||||
mLeftTextWidget->addText("left texxxt ");
|
||||
mLeftTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditReadOnly(true);
|
||||
mRightTextWidget->setEditStatic(true);
|
||||
mLeftTextWidget->setEditStatic(true);
|
||||
mRightTextWidget->addText("Right texxt ");
|
||||
|
||||
//std::list<std::string> list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn");
|
||||
//std::list<std::string> list = formatText();
|
||||
//displayLeftText(list.front());
|
||||
|
||||
MyGUI::WindowPtr t = static_cast<MyGUI::WindowPtr>(mMainWidget);
|
||||
t->eventWindowChangeCoord = MyGUI::newDelegate(this, &JournalWindow::onWindowResize);
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::open()
|
||||
{
|
||||
mPageNumber = 0;
|
||||
if(mWindowManager.getEnvironment().mJournal->begin()!=mWindowManager.getEnvironment().mJournal->end())
|
||||
{
|
||||
book journal;
|
||||
journal.endLine = 0;
|
||||
|
||||
for(std::deque<MWDialogue::StampedJournalEntry>::const_iterator it = mWindowManager.getEnvironment().mJournal->begin();it!=mWindowManager.getEnvironment().mJournal->end();it++)
|
||||
{
|
||||
std::string a = it->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
journal = formatText(a,journal,10,17);
|
||||
journal.endLine = journal.endLine +1;
|
||||
journal.pages.back() = journal.pages.back() + std::string("\n");
|
||||
}
|
||||
//std::string a = mWindowManager.getEnvironment().mJournal->begin()->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
//std::list<std::string> journal = formatText(a,10,20,1);
|
||||
bool left = true;
|
||||
for(std::list<std::string>::iterator it = journal.pages.begin(); it != journal.pages.end();it++)
|
||||
{
|
||||
if(left)
|
||||
{
|
||||
leftPages.push_back(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightPages.push_back(*it);
|
||||
}
|
||||
left = !left;
|
||||
}
|
||||
if(!left) rightPages.push_back("");
|
||||
|
||||
mPageNumber = leftPages.size()-1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << mWindowManager.getEnvironment().mJournal->begin()->getText(mWindowManager.getEnvironment().mWorld->getStore());
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::onWindowResize(MyGUI::Window* window)
|
||||
{
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayLeftText(std::string text)
|
||||
{
|
||||
mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength());
|
||||
mLeftTextWidget->addText(text);
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::displayRightText(std::string text)
|
||||
{
|
||||
mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength());
|
||||
mRightTextWidget->addText(text);
|
||||
}
|
||||
|
||||
|
||||
void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender)
|
||||
{
|
||||
if(mPageNumber < int(leftPages.size())-1)
|
||||
{
|
||||
mPageNumber = mPageNumber + 1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender)
|
||||
{
|
||||
if(mPageNumber > 0)
|
||||
{
|
||||
mPageNumber = mPageNumber - 1;
|
||||
displayLeftText(leftPages[mPageNumber]);
|
||||
displayRightText(rightPages[mPageNumber]);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
#ifndef MWGUI_JOURNAL_H
|
||||
#define MWGUI_JOURNAL_H
|
||||
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "window_base.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
|
||||
class JournalWindow : public WindowBase
|
||||
{
|
||||
public:
|
||||
JournalWindow(WindowManager& parWindowManager);
|
||||
void open();
|
||||
|
||||
private:
|
||||
enum ColorStyle
|
||||
{
|
||||
CS_Sub,
|
||||
CS_Normal,
|
||||
CS_Super
|
||||
};
|
||||
|
||||
void onWindowResize(MyGUI::Window* window);
|
||||
|
||||
void displayLeftText(std::string text);
|
||||
void displayRightText(std::string text);
|
||||
|
||||
|
||||
/**
|
||||
*Called when next/prev button is used.
|
||||
*/
|
||||
void notifyNextPage(MyGUI::WidgetPtr _sender);
|
||||
void notifyPrevPage(MyGUI::WidgetPtr _sender);
|
||||
|
||||
static const int lineHeight;
|
||||
|
||||
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
|
||||
MyGUI::VScrollPtr skillScrollerWidget;
|
||||
int lastPos, clientHeight;
|
||||
MyGUI::EditPtr mLeftTextWidget;
|
||||
MyGUI::EditPtr mRightTextWidget;
|
||||
MyGUI::ButtonPtr mPrevBtn;
|
||||
MyGUI::ButtonPtr mNextBtn;
|
||||
std::vector<std::string> leftPages;
|
||||
std::vector<std::string> rightPages;
|
||||
int mPageNumber; //store the number of the current left page
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,125 @@
|
||||
#include "actors.hpp"
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace MWRender;
|
||||
using namespace NifOgre;
|
||||
|
||||
void Actors::setMwRoot(Ogre::SceneNode* root){
|
||||
mMwRoot = root;
|
||||
}
|
||||
void Actors::insertNPC(const MWWorld::Ptr& ptr){
|
||||
|
||||
insertBegin(ptr, true, true);
|
||||
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend);
|
||||
|
||||
mAllActors[ptr] = anim;
|
||||
}
|
||||
void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){
|
||||
Ogre::SceneNode* cellnode;
|
||||
if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end())
|
||||
{
|
||||
//Create the scenenode and put it in the map
|
||||
cellnode = mMwRoot->createChildSceneNode();
|
||||
mCellSceneNodes[ptr.getCell()] = cellnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellnode = mCellSceneNodes[ptr.getCell()];
|
||||
}
|
||||
|
||||
Ogre::SceneNode* insert = cellnode->createChildSceneNode();
|
||||
const float *f = ptr.getRefData().getPosition().pos;
|
||||
insert->setPosition(f[0], f[1], f[2]);
|
||||
insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale);
|
||||
|
||||
// Convert MW rotation to a quaternion:
|
||||
f = ptr.getCellRef().pos.rot;
|
||||
|
||||
// Rotate around X axis
|
||||
Quaternion xr(Radian(-f[0]), Vector3::UNIT_X);
|
||||
|
||||
// Rotate around Y axis
|
||||
Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y);
|
||||
|
||||
// Rotate around Z axis
|
||||
Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z);
|
||||
|
||||
// Rotates first around z, then y, then x
|
||||
insert->setOrientation(xr*yr*zr);
|
||||
if (!enabled)
|
||||
insert->setVisible (false);
|
||||
ptr.getRefData().setBaseNode(insert);
|
||||
|
||||
|
||||
}
|
||||
void Actors::insertCreature (const MWWorld::Ptr& ptr){
|
||||
|
||||
insertBegin(ptr, true, true);
|
||||
CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend);
|
||||
//mAllActors.insert(std::pair<MWWorld::Ptr, Animation*>(ptr,anim));
|
||||
mAllActors[ptr] = anim;
|
||||
//mAllActors.push_back(&anim);*/
|
||||
}
|
||||
|
||||
bool Actors::deleteObject (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
delete mAllActors[ptr];
|
||||
mAllActors.erase(ptr);
|
||||
if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode())
|
||||
{
|
||||
|
||||
Ogre::SceneNode *parent = base->getParentSceneNode();
|
||||
|
||||
for (std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *>::const_iterator iter (
|
||||
mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter)
|
||||
if (iter->second==parent)
|
||||
{
|
||||
base->removeAndDestroyAllChildren();
|
||||
mRend.getScene()->destroySceneNode (base);
|
||||
ptr.getRefData().setBaseNode (0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Actors::removeCell(MWWorld::Ptr::CellStore* store){
|
||||
if(mCellSceneNodes.find(store) != mCellSceneNodes.end())
|
||||
{
|
||||
Ogre::SceneNode* base = mCellSceneNodes[store];
|
||||
base->removeAndDestroyAllChildren();
|
||||
mCellSceneNodes.erase(store);
|
||||
mRend.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
}
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
|
||||
{
|
||||
if(iter->first.getCell() == store){
|
||||
delete iter->second;
|
||||
mAllActors.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){
|
||||
if(mAllActors.find(ptr) != mAllActors.end())
|
||||
mAllActors[ptr]->startScript(groupName, mode, number);
|
||||
}
|
||||
void Actors::skipAnimation (const MWWorld::Ptr& ptr){
|
||||
if(mAllActors.find(ptr) != mAllActors.end())
|
||||
mAllActors[ptr]->stopScript();
|
||||
}
|
||||
void Actors::update (float duration){
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
|
||||
{
|
||||
(iter->second)->runAnimation(duration);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
#ifndef _GAME_RENDER_ACTORS_H
|
||||
#define _GAME_RENDER_ACTORS_H
|
||||
|
||||
#include "components/esm_store/cell_store.hpp"
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
|
||||
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "npcanimation.hpp"
|
||||
#include "creatureanimation.hpp"
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
namespace MWRender{
|
||||
class Actors{
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
|
||||
Ogre::SceneNode* mMwRoot;
|
||||
MWWorld::Environment& mEnvironment;
|
||||
std::map<MWWorld::Ptr, Animation*> mAllActors;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){}
|
||||
~Actors(){}
|
||||
void setMwRoot(Ogre::SceneNode* root);
|
||||
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
|
||||
void insertCreature (const MWWorld::Ptr& ptr);
|
||||
void insertNPC(const MWWorld::Ptr& ptr);
|
||||
bool deleteObject (const MWWorld::Ptr& ptr);
|
||||
///< \return found?
|
||||
|
||||
void removeCell(MWWorld::Ptr::CellStore* store);
|
||||
|
||||
void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode,
|
||||
int number = 1);
|
||||
///< Run animation for a MW-reference. Calls to this function for references that are currently not
|
||||
/// in the rendered scene should be ignored.
|
||||
///
|
||||
/// \param mode: 0 normal, 1 immediate start, 2 immediate loop
|
||||
/// \param number How offen the animation should be run
|
||||
|
||||
void skipAnimation (const MWWorld::Ptr& ptr);
|
||||
///< Skip the animation for the given MW-reference for one frame. Calls to this function for
|
||||
/// references that are currently not in the rendered scene should be ignored.
|
||||
|
||||
void update (float duration);
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -0,0 +1,477 @@
|
||||
#include "animation.hpp"
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
std::map<std::string, int> Animation::mUniqueIDs;
|
||||
|
||||
Animation::~Animation(){
|
||||
}
|
||||
|
||||
std::string Animation::getUniqueID(std::string mesh){
|
||||
int counter;
|
||||
std::string copy = mesh;
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
|
||||
if(mUniqueIDs.find(copy) == mUniqueIDs.end()){
|
||||
counter = mUniqueIDs[copy] = 0;
|
||||
}
|
||||
else{
|
||||
mUniqueIDs[copy] = mUniqueIDs[copy] + 1;
|
||||
counter = mUniqueIDs[copy];
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if(counter > 99 && counter < 1000)
|
||||
out << "0";
|
||||
else if(counter > 9)
|
||||
out << "00";
|
||||
else
|
||||
out << "000";
|
||||
out << counter;
|
||||
return out.str();
|
||||
}
|
||||
void Animation::startScript(std::string groupname, int mode, int loops){
|
||||
//If groupname is recognized set animate to true
|
||||
//Set the start time and stop time
|
||||
//How many times to loop
|
||||
if(groupname == "all"){
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
}
|
||||
else if(textmappings){
|
||||
|
||||
std::string startName = groupname + ": loop start";
|
||||
std::string stopName = groupname + ": loop stop";
|
||||
|
||||
bool first = false;
|
||||
|
||||
if(loops > 1){
|
||||
startName = groupname + ": loop start";
|
||||
stopName = groupname + ": loop stop";
|
||||
|
||||
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
|
||||
|
||||
std::string current = iter->first.substr(0, startName.size());
|
||||
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
|
||||
std::string current2 = iter->first.substr(0, stopName.size());
|
||||
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
|
||||
|
||||
if(current == startName){
|
||||
startTime = iter->second;
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
first = true;
|
||||
}
|
||||
if(current2 == stopName){
|
||||
stopTime = iter->second;
|
||||
if(first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!first){
|
||||
startName = groupname + ": start";
|
||||
stopName = groupname + ": stop";
|
||||
|
||||
for(std::map<std::string, float>::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){
|
||||
|
||||
std::string current = iter->first.substr(0, startName.size());
|
||||
std::transform(current.begin(), current.end(), current.begin(), ::tolower);
|
||||
std::string current2 = iter->first.substr(0, stopName.size());
|
||||
std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower);
|
||||
|
||||
if(current == startName){
|
||||
startTime = iter->second;
|
||||
animate = loops;
|
||||
time = startTime;
|
||||
first = true;
|
||||
}
|
||||
if(current2 == stopName){
|
||||
stopTime = iter->second;
|
||||
if(first)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
void Animation::stopScript(){
|
||||
animate = 0;
|
||||
}
|
||||
|
||||
void Animation::handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){
|
||||
shapeNumber = 0;
|
||||
|
||||
std::vector<Nif::NiTriShapeCopy>::iterator allshapesiter;
|
||||
for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++)
|
||||
|
||||
{
|
||||
//std::map<unsigned short, PosAndRot> vecPosRot;
|
||||
|
||||
Nif::NiTriShapeCopy& copy = *allshapesiter;
|
||||
std::vector<Ogre::Vector3>* allvertices = ©.vertices;
|
||||
std::vector<Ogre::Vector3>* allnormals = ©.normals;
|
||||
|
||||
|
||||
|
||||
//std::set<unsigned int> vertices;
|
||||
//std::set<unsigned int> normals;
|
||||
//std::vector<Nif::NiSkinData::BoneInfoCopy> boneinfovector = copy.boneinfo;
|
||||
std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >* verticesToChange = ©.vertsToWeights;
|
||||
|
||||
//std::cout << "Name " << copy.sname << "\n";
|
||||
Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0);
|
||||
Ogre::Real* pReal = static_cast<Ogre::Real*>(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
|
||||
|
||||
|
||||
std::vector<Ogre::Vector3> initialVertices = copy.morph.getInitialVertices();
|
||||
//Each shape has multiple indices
|
||||
if(initialVertices.size() )
|
||||
{
|
||||
|
||||
if(copy.vertices.size() == initialVertices.size())
|
||||
{
|
||||
//Create if it doesn't already exist
|
||||
if(shapeIndexI.size() == static_cast<std::size_t> (shapeNumber))
|
||||
{
|
||||
std::vector<int> vec;
|
||||
shapeIndexI.push_back(vec);
|
||||
}
|
||||
if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){
|
||||
float x;
|
||||
for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){
|
||||
int j = 0;
|
||||
if(shapeIndexI[shapeNumber].size() <= i)
|
||||
shapeIndexI[shapeNumber].push_back(0);
|
||||
|
||||
|
||||
if(timeIndex(time,copy.morph.getRelevantTimes()[i],(shapeIndexI[shapeNumber])[i], j, x)){
|
||||
int indexI = (shapeIndexI[shapeNumber])[i];
|
||||
std::vector<Ogre::Vector3> relevantData = (copy.morph.getRelevantData()[i]);
|
||||
float v1 = relevantData[indexI].x;
|
||||
float v2 = relevantData[j].x;
|
||||
float t = v1 + (v2 - v1) * x;
|
||||
if ( t < 0 ) t = 0;
|
||||
if ( t > 1 ) t = 1;
|
||||
if( t != 0 && initialVertices.size() == copy.morph.getAdditionalVertices()[i].size())
|
||||
{
|
||||
for (unsigned int v = 0; v < initialVertices.size(); v++){
|
||||
initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
allvertices = &initialVertices;
|
||||
}
|
||||
shapeNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(verticesToChange->size() > 0){
|
||||
|
||||
for(std::map<int, std::vector<Nif::NiSkinData::IndividualWeight> >::iterator iter = verticesToChange->begin();
|
||||
iter != verticesToChange->end(); iter++)
|
||||
{
|
||||
std::vector<Nif::NiSkinData::IndividualWeight> inds = iter->second;
|
||||
int verIndex = iter->first;
|
||||
Ogre::Vector3 currentVertex = (*allvertices)[verIndex];
|
||||
Ogre::Vector3 currentNormal = (*allnormals)[verIndex];
|
||||
Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]);
|
||||
Ogre::Bone *bonePtr = 0;
|
||||
|
||||
|
||||
|
||||
Ogre::Vector3 vecPos;
|
||||
Ogre::Quaternion vecRot;
|
||||
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot>::iterator result = vecRotPos.find(boneinfocopy);
|
||||
|
||||
if(result == vecRotPos.end()){
|
||||
bonePtr = skel->getBone(boneinfocopy->bonename);
|
||||
|
||||
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
|
||||
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
|
||||
|
||||
|
||||
PosAndRot both;
|
||||
both.vecPos = vecPos;
|
||||
both.vecRot = vecRot;
|
||||
vecRotPos[boneinfocopy] = both;
|
||||
|
||||
}
|
||||
else{
|
||||
PosAndRot both = result->second;
|
||||
vecPos = both.vecPos;
|
||||
vecRot = both.vecRot;
|
||||
}
|
||||
|
||||
Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight;
|
||||
|
||||
|
||||
|
||||
for(std::size_t i = 1; i < inds.size(); i++){
|
||||
boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]);
|
||||
result = vecRotPos.find(boneinfocopy);
|
||||
|
||||
|
||||
if(result == vecRotPos.end()){
|
||||
bonePtr = skel->getBone(boneinfocopy->bonename);
|
||||
vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans;
|
||||
vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation;
|
||||
|
||||
PosAndRot both;
|
||||
both.vecPos = vecPos;
|
||||
both.vecRot = vecRot;
|
||||
vecRotPos[boneinfocopy] = both;
|
||||
|
||||
}
|
||||
else{
|
||||
PosAndRot both = result->second;
|
||||
vecPos = both.vecPos;
|
||||
vecRot = both.vecRot;
|
||||
}
|
||||
|
||||
|
||||
absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight;
|
||||
|
||||
|
||||
}
|
||||
Ogre::Real* addr = (pReal + 3 * verIndex);
|
||||
*addr = absVertPos.x;
|
||||
*(addr+1) = absVertPos.y;
|
||||
*(addr+2) = absVertPos.z;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(copy.bonename);
|
||||
Ogre::Quaternion shaperot = copy.trafo.rotation;
|
||||
Ogre::Vector3 shapetrans = copy.trafo.trans;
|
||||
float shapescale = copy.trafo.scale;
|
||||
std::vector<std::string> boneSequence = copy.boneSequence;
|
||||
|
||||
Ogre::Vector3 transmult;
|
||||
Ogre::Quaternion rotmult;
|
||||
float scale;
|
||||
if(boneSequence.size() > 0){
|
||||
std::vector<std::string>::iterator boneSequenceIter = boneSequence.begin();
|
||||
if(skel->hasBone(*boneSequenceIter)){
|
||||
Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
|
||||
|
||||
|
||||
|
||||
|
||||
transmult = bonePtr->getPosition();
|
||||
rotmult = bonePtr->getOrientation();
|
||||
scale = bonePtr->getScale().x;
|
||||
boneSequenceIter++;
|
||||
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
|
||||
{
|
||||
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
|
||||
Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter);
|
||||
// Computes C = B + AxC*scale
|
||||
transmult = transmult + rotmult * bonePtr->getPosition();
|
||||
rotmult = rotmult * bonePtr->getOrientation();
|
||||
scale = scale * bonePtr->getScale().x;
|
||||
}
|
||||
//std::cout << "Bone:" << *boneSequenceIter << " ";
|
||||
}
|
||||
transmult = transmult + rotmult * shapetrans;
|
||||
rotmult = rotmult * shaperot;
|
||||
scale = shapescale * scale;
|
||||
|
||||
//std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transmult = shapetrans;
|
||||
rotmult = shaperot;
|
||||
scale = shapescale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Computes C = B + AxC*scale
|
||||
// final_vector = old_vector + old_rotation*new_vector*old_scale/
|
||||
|
||||
for(unsigned int i = 0; i < allvertices->size(); i++){
|
||||
Ogre::Vector3 current = transmult + rotmult * (*allvertices)[i];
|
||||
Ogre::Real* addr = pReal + i * 3;
|
||||
*addr = current.x;
|
||||
*(addr+1) = current.y;
|
||||
*(addr + 2) = current.z;
|
||||
|
||||
}/*
|
||||
for(int i = 0; i < allnormals.size(); i++){
|
||||
Ogre::Vector3 current =rotmult * allnormals[i];
|
||||
Ogre::Real* addr = pRealNormal + i * 3;
|
||||
*addr = current.x;
|
||||
*(addr+1) = current.y;
|
||||
*(addr + 2) = current.z;
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
vbuf->unlock();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
bool Animation::timeIndex( float time, std::vector<float> times, int & i, int & j, float & x ){
|
||||
int count;
|
||||
if ( (count = times.size()) > 0 )
|
||||
{
|
||||
if ( time <= times[0] )
|
||||
{
|
||||
i = j = 0;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
if ( time >= times[count - 1] )
|
||||
{
|
||||
i = j = count - 1;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( i < 0 || i >= count )
|
||||
i = 0;
|
||||
|
||||
float tI = times[i];
|
||||
if ( time > tI )
|
||||
{
|
||||
j = i + 1;
|
||||
float tJ;
|
||||
while ( time >= ( tJ = times[j]) )
|
||||
{
|
||||
i = j++;
|
||||
tI = tJ;
|
||||
}
|
||||
x = ( time - tI ) / ( tJ - tI );
|
||||
return true;
|
||||
}
|
||||
else if ( time < tI )
|
||||
{
|
||||
j = i - 1;
|
||||
float tJ;
|
||||
while ( time <= ( tJ = times[j] ) )
|
||||
{
|
||||
i = j--;
|
||||
tI = tJ;
|
||||
}
|
||||
x = ( time - tI ) / ( tJ - tI );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = i;
|
||||
x = 0.0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void Animation::handleAnimationTransforms(){
|
||||
Ogre::SkeletonInstance* skel = base->getSkeleton();
|
||||
|
||||
|
||||
Ogre::Bone* b = skel->getRootBone();
|
||||
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick
|
||||
|
||||
skel->_updateTransforms();
|
||||
//skel->_notifyManualBonesDirty();
|
||||
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
//base->_updateAnimation();
|
||||
//base->_notifyMoved();
|
||||
|
||||
for(unsigned int i = 0; i < entityparts.size(); i++){
|
||||
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
|
||||
|
||||
Ogre::Bone* b = skel->getRootBone();
|
||||
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
||||
|
||||
entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
||||
}
|
||||
|
||||
|
||||
std::vector<Nif::NiKeyframeData>::iterator iter;
|
||||
int slot = 0;
|
||||
if(transformations){
|
||||
for(iter = transformations->begin(); iter != transformations->end(); iter++){
|
||||
if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime())
|
||||
{
|
||||
slot++;
|
||||
continue;
|
||||
}
|
||||
|
||||
float x;
|
||||
float x2;
|
||||
|
||||
std::vector<Ogre::Quaternion> quats = iter->getQuat();
|
||||
|
||||
std::vector<float> ttime = iter->gettTime();
|
||||
std::vector<float>::iterator ttimeiter = ttime.begin();
|
||||
|
||||
std::vector<float> rtime = iter->getrTime();
|
||||
int rindexJ = 0;
|
||||
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
|
||||
int tindexJ = 0;
|
||||
|
||||
|
||||
std::vector<Ogre::Vector3> translist1 = iter->getTranslist1();
|
||||
|
||||
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
|
||||
|
||||
Ogre::Vector3 t;
|
||||
Ogre::Quaternion r;
|
||||
|
||||
bool bTrans = translist1.size() > 0;
|
||||
if(bTrans){
|
||||
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
||||
Ogre::Vector3 v2 = translist1[tindexJ];
|
||||
t = (v1 + (v2 - v1) * x);
|
||||
|
||||
}
|
||||
|
||||
bool bQuats = quats.size() > 0;
|
||||
if(bQuats){
|
||||
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
||||
}
|
||||
skel = base->getSkeleton();
|
||||
if(skel->hasBone(iter->getBonename())){
|
||||
Ogre::Bone* bone = skel->getBone(iter->getBonename());
|
||||
if(bTrans)
|
||||
bone->setPosition(t);
|
||||
if(bQuats)
|
||||
bone->setOrientation(r);
|
||||
|
||||
|
||||
|
||||
skel->_updateTransforms();
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
|
||||
}
|
||||
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
#ifndef _GAME_RENDER_ANIMATION_H
|
||||
#define _GAME_RENDER_ANIMATION_H
|
||||
#include <components/nif/data.hpp>
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/actiontalk.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include <components/nif/node.hpp>
|
||||
#include <map>
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
struct PosAndRot{
|
||||
Ogre::Quaternion vecRot;
|
||||
Ogre::Vector3 vecPos;
|
||||
};
|
||||
|
||||
class Animation{
|
||||
|
||||
protected:
|
||||
Ogre::SceneNode* insert;
|
||||
OEngine::Render::OgreRenderer &mRend;
|
||||
MWWorld::Environment& mEnvironment;
|
||||
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot> vecRotPos;
|
||||
static std::map<std::string, int> mUniqueIDs;
|
||||
|
||||
|
||||
std::vector<std::vector<Nif::NiTriShapeCopy>* > shapeparts; //All the NiTriShape data that we need for animating an npc
|
||||
|
||||
float time;
|
||||
float startTime;
|
||||
float stopTime;
|
||||
int animate;
|
||||
//Represents a rotation index for each bone
|
||||
std::vector<int>rindexI;
|
||||
//Represents a translation index for each bone
|
||||
std::vector<int>tindexI;
|
||||
|
||||
//Only shapes with morphing data will use a shape number
|
||||
int shapeNumber;
|
||||
std::vector<std::vector<int> > shapeIndexI;
|
||||
|
||||
//Ogre::SkeletonInstance* skel;
|
||||
std::vector<Nif::NiTriShapeCopy>* shapes; //All the NiTriShapeData for a creature
|
||||
std::vector<Ogre::Entity*> entityparts;
|
||||
|
||||
|
||||
std::vector<Nif::NiKeyframeData>* transformations;
|
||||
std::map<std::string,float>* textmappings;
|
||||
Ogre::Entity* base;
|
||||
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
|
||||
void handleAnimationTransforms();
|
||||
bool timeIndex( float time, std::vector<float> times, int & i, int & j, float & x );
|
||||
std::string getUniqueID(std::string mesh);
|
||||
|
||||
public:
|
||||
Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend): mRend(_rend), mEnvironment(_env), animate(0){};
|
||||
virtual void runAnimation(float timepassed) = 0;
|
||||
void startScript(std::string groupname, int mode, int loops);
|
||||
void stopScript();
|
||||
|
||||
|
||||
~Animation();
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -0,0 +1,63 @@
|
||||
#include "creatureanimation.hpp"
|
||||
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace NifOgre;
|
||||
namespace MWRender{
|
||||
|
||||
CreatureAnimation::~CreatureAnimation(){
|
||||
|
||||
}
|
||||
CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){
|
||||
insert = ptr.getRefData().getBaseNode();
|
||||
ESMS::LiveCellRef<ESM::Creature, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
assert (ref->base != NULL);
|
||||
if(!ref->base->model.empty()){
|
||||
const std::string &mesh = "meshes\\" + ref->base->model;
|
||||
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
|
||||
NifOgre::NIFLoader::load(meshNumbered);
|
||||
base = mRend.getScene()->createEntity(meshNumbered);
|
||||
std::string meshZero = mesh + "0000>|";
|
||||
|
||||
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){
|
||||
|
||||
for(std::size_t init = 0; init < transformations->size(); init++){
|
||||
rindexI.push_back(0);
|
||||
tindexI.push_back(0);
|
||||
}
|
||||
stopTime = transformations->begin()->getStopTime();
|
||||
startTime = transformations->begin()->getStartTime();
|
||||
shapes = (NIFLoader::getSingletonPtr())->getShapes(meshZero);
|
||||
}
|
||||
textmappings = NIFLoader::getSingletonPtr()->getTextIndices(meshZero);
|
||||
insert->attachObject(base);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAnimation::runAnimation(float timepassed){
|
||||
vecRotPos.clear();
|
||||
if(animate > 0){
|
||||
//Add the amount of time passed to time
|
||||
|
||||
//Handle the animation transforms dependent on time
|
||||
|
||||
//Handle the shapes dependent on animation transforms
|
||||
time += timepassed;
|
||||
if(time >= stopTime){
|
||||
animate--;
|
||||
//std::cout << "Stopping the animation\n";
|
||||
if(animate == 0)
|
||||
time = stopTime;
|
||||
else
|
||||
time = startTime + (time - stopTime);
|
||||
}
|
||||
|
||||
handleAnimationTransforms();
|
||||
handleShapes(shapes, base, base->getSkeleton());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#ifndef _GAME_RENDER_CREATUREANIMATION_H
|
||||
#define _GAME_RENDER_CREATUREANIMATION_H
|
||||
|
||||
#include "animation.hpp"
|
||||
#include <components/nif/node.hpp>
|
||||
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class CreatureAnimation: public Animation{
|
||||
|
||||
public:
|
||||
~CreatureAnimation();
|
||||
CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||
virtual void runAnimation(float timepassed);
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,2 +0,0 @@
|
||||
#include "creatures.hpp"
|
||||
using namespace MWRender;
|
@ -1,10 +0,0 @@
|
||||
#ifndef _GAME_RENDER_CREATURES_H
|
||||
#define _GAME_RENDER_CREATURES_H
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
|
||||
namespace MWRender{
|
||||
class Creatures{
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -0,0 +1,282 @@
|
||||
#include "npcanimation.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
|
||||
using namespace Ogre;
|
||||
using namespace NifOgre;
|
||||
namespace MWRender{
|
||||
NpcAnimation::~NpcAnimation(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){
|
||||
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
|
||||
ptr.get<ESM::NPC>();
|
||||
|
||||
//Part selection on last character of the file string
|
||||
// " Tri Chest
|
||||
// * Tri Tail
|
||||
// : Tri Left Foot
|
||||
// < Tri Right Foot
|
||||
// > Tri Left Hand
|
||||
// ? Tri Right Hand
|
||||
// | Normal
|
||||
|
||||
//Mirroring Parts on second to last character
|
||||
//suffix == '*'
|
||||
// vector = Ogre::Vector3(-1,1,1);
|
||||
// suffix == '?'
|
||||
// vector = Ogre::Vector3(1,-1,1);
|
||||
// suffix == '<'
|
||||
// vector = Ogre::Vector3(1,1,-1);
|
||||
|
||||
|
||||
std::string hairID = ref->base->hair;
|
||||
std::string headID = ref->base->head;
|
||||
std::string npcName = ref->base->name;
|
||||
//ESMStore::Races r =
|
||||
const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race);
|
||||
|
||||
|
||||
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
||||
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
|
||||
bool female = tolower(secondtolast) == 'f';
|
||||
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
|
||||
|
||||
/*std::cout << "Race: " << ref->base->race ;
|
||||
if(female){
|
||||
std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n";
|
||||
}
|
||||
else{
|
||||
std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n";
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
std::string smodel = "meshes\\base_anim.nif";
|
||||
if(beast)
|
||||
smodel = "meshes\\base_animkna.nif";
|
||||
|
||||
insert = ptr.getRefData().getBaseNode();
|
||||
assert(insert);
|
||||
|
||||
NifOgre::NIFLoader::load(smodel);
|
||||
|
||||
base = mRend.getScene()->createEntity(smodel);
|
||||
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones
|
||||
//stay in the same place when we skipanim, or open a gui window
|
||||
|
||||
|
||||
|
||||
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){
|
||||
|
||||
for(unsigned int init = 0; init < transformations->size(); init++){
|
||||
rindexI.push_back(0);
|
||||
tindexI.push_back(0);
|
||||
}
|
||||
|
||||
stopTime = transformations->begin()->getStopTime();
|
||||
startTime = transformations->begin()->getStartTime();
|
||||
}
|
||||
textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel);
|
||||
insert->attachObject(base);
|
||||
|
||||
if(female)
|
||||
insert->scale(race->data.height.female, race->data.height.female, race->data.height.female);
|
||||
else
|
||||
insert->scale(race->data.height.male, race->data.height.male, race->data.height.male);
|
||||
std::string headModel = "meshes\\" +
|
||||
mEnvironment.mWorld->getStore().bodyParts.find(headID)->model;
|
||||
|
||||
std::string hairModel = "meshes\\" +
|
||||
mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model;
|
||||
const ESM::BodyPart *chest = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest");
|
||||
const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg");
|
||||
const ESM::BodyPart *groin = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin");
|
||||
const ESM::BodyPart *arml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); //We need two
|
||||
const ESM::BodyPart *neck = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck");
|
||||
const ESM::BodyPart *knee = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee");
|
||||
const ESM::BodyPart *ankle = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle");
|
||||
const ESM::BodyPart *foot = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot");
|
||||
const ESM::BodyPart *feet = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet");
|
||||
const ESM::BodyPart *tail = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail");
|
||||
const ESM::BodyPart *wristl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two
|
||||
const ESM::BodyPart *forearml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two
|
||||
const ESM::BodyPart *handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two
|
||||
const ESM::BodyPart *hair = mEnvironment.mWorld->getStore().bodyParts.search(hairID);
|
||||
const ESM::BodyPart *head = mEnvironment.mWorld->getStore().bodyParts.search(headID);
|
||||
if(bodyRaceID == "b_n_argonian_f_")
|
||||
forearml = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two
|
||||
if(!handl)
|
||||
handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands");
|
||||
//const ESM::BodyPart* claviclel = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "clavicle");
|
||||
//const ESM::BodyPart* clavicler = claviclel;
|
||||
const ESM::BodyPart* handr = handl;
|
||||
const ESM::BodyPart* forearmr = forearml;
|
||||
const ESM::BodyPart* wristr = wristl;
|
||||
const ESM::BodyPart* armr = arml;
|
||||
|
||||
|
||||
if(upperleg){
|
||||
insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg");
|
||||
insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg");
|
||||
|
||||
}
|
||||
if(foot){
|
||||
if(bodyRaceID.compare("b_n_khajiit_m_") == 0)
|
||||
{
|
||||
feet = foot;
|
||||
}
|
||||
else
|
||||
{
|
||||
insertBoundedPart("meshes\\" + foot->model, "Right Foot");
|
||||
insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot");
|
||||
}
|
||||
}
|
||||
if(groin){
|
||||
insertBoundedPart("meshes\\" + groin->model, "Groin");
|
||||
}
|
||||
if(knee)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e
|
||||
insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e
|
||||
|
||||
}
|
||||
if(ankle){
|
||||
|
||||
insertBoundedPart("meshes\\" + ankle->model + "*|", "Left Ankle"); //Ogre::Quaternion(Ogre::Radian(3.14 / 4), Ogre::Vector3(1, 0, 0)),blank); //1,0,0, blank);
|
||||
insertBoundedPart("meshes\\" + ankle->model, "Right Ankle");
|
||||
}
|
||||
if (armr){
|
||||
insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm");
|
||||
}
|
||||
if(arml){
|
||||
insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm");
|
||||
}
|
||||
|
||||
if (forearmr)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm");
|
||||
}
|
||||
if(forearml)
|
||||
insertBoundedPart("meshes\\" + forearml->model + "*|", "Left Forearm");
|
||||
|
||||
if (wristr)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + wristr->model, "Right Wrist");
|
||||
}
|
||||
|
||||
if(wristl)
|
||||
insertBoundedPart("meshes\\" + wristl->model + "*|", "Left Wrist");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*if(claviclel)
|
||||
insertBoundedPart("meshes\\" + claviclel->model + "*|", "Left Clavicle", base);
|
||||
if(clavicler)
|
||||
insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/
|
||||
|
||||
if(neck)
|
||||
{
|
||||
insertBoundedPart("meshes\\" + neck->model, "Neck");
|
||||
}
|
||||
if(head)
|
||||
insertBoundedPart("meshes\\" + head->model, "Head");
|
||||
if(hair)
|
||||
insertBoundedPart("meshes\\" + hair->model, "Head");
|
||||
|
||||
if (chest){
|
||||
insertFreePart("meshes\\" + chest->model, ">\"", insert);
|
||||
|
||||
|
||||
}
|
||||
if (handr){
|
||||
insertFreePart("meshes\\" + handr->model , ">?", insert);
|
||||
|
||||
}
|
||||
if (handl){
|
||||
insertFreePart("meshes\\" + handl->model, ">>", insert);
|
||||
|
||||
}
|
||||
if(tail){
|
||||
insertFreePart("meshes\\" + tail->model, ">*", insert);
|
||||
}
|
||||
if(feet){
|
||||
std::string num = getUniqueID(feet->model);
|
||||
insertFreePart("meshes\\" + feet->model,"><", insert);
|
||||
insertFreePart("meshes\\" + feet->model,">:", insert);
|
||||
}
|
||||
//originalpos = insert->_getWorldAABB().getCenter();
|
||||
//originalscenenode = insert->getPosition();
|
||||
}
|
||||
|
||||
Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){
|
||||
|
||||
NIFLoader::load(mesh);
|
||||
Entity* ent = mRend.getScene()->createEntity(mesh);
|
||||
|
||||
base->attachObjectToBone(bonename, ent);
|
||||
return ent;
|
||||
}
|
||||
void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert){
|
||||
std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix;
|
||||
NIFLoader::load(meshNumbered);
|
||||
|
||||
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered);
|
||||
|
||||
|
||||
|
||||
|
||||
insert->attachObject(ent);
|
||||
entityparts.push_back(ent);
|
||||
shapes = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix));
|
||||
if(shapes){
|
||||
shapeparts.push_back(shapes);
|
||||
handleShapes(shapes, ent, base->getSkeleton());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NpcAnimation::runAnimation(float timepassed){
|
||||
|
||||
//1. Add the amount of time passed to time
|
||||
|
||||
//2. Handle the animation transforms dependent on time
|
||||
|
||||
//3. Handle the shapes dependent on animation transforms
|
||||
if(animate > 0){
|
||||
time += timepassed;
|
||||
|
||||
if(time > stopTime){
|
||||
animate--;
|
||||
|
||||
if(animate == 0)
|
||||
time = stopTime;
|
||||
else
|
||||
time = startTime + (time - stopTime);
|
||||
}
|
||||
|
||||
handleAnimationTransforms();
|
||||
|
||||
std::vector<std::vector<Nif::NiTriShapeCopy>*>::iterator shapepartsiter = shapeparts.begin();
|
||||
std::vector<Ogre::Entity*>::iterator entitypartsiter = entityparts.begin();
|
||||
while(shapepartsiter != shapeparts.end())
|
||||
{
|
||||
vecRotPos.clear();
|
||||
std::vector<Nif::NiTriShapeCopy>* shapes = *shapepartsiter;
|
||||
Ogre::Entity* theentity = *entitypartsiter;
|
||||
|
||||
|
||||
handleShapes(shapes, theentity, base->getSkeleton());
|
||||
shapepartsiter++;
|
||||
entitypartsiter++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
#ifndef _GAME_RENDER_NPCANIMATION_H
|
||||
#define _GAME_RENDER_NPCANIMATION_H
|
||||
#include "animation.hpp"
|
||||
#include <components/nif/data.hpp>
|
||||
#include <components/nif/node.hpp>
|
||||
#include <components/nif/property.hpp>
|
||||
#include <components/nif/controller.hpp>
|
||||
#include <components/nif/extra.hpp>
|
||||
|
||||
#include "../mwworld/refdata.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "components/nifogre/ogre_nif_loader.hpp"
|
||||
|
||||
namespace MWRender{
|
||||
|
||||
class NpcAnimation: public Animation{
|
||||
|
||||
|
||||
|
||||
public:
|
||||
NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend);
|
||||
~NpcAnimation();
|
||||
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename);
|
||||
void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert);
|
||||
virtual void runAnimation(float timepassed);
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,2 +0,0 @@
|
||||
#include "npcs.hpp"
|
||||
using namespace MWRender;
|
@ -1,9 +0,0 @@
|
||||
#ifndef _GAME_RENDER_NPCS_H
|
||||
#define _GAME_RENDER_NPCS_H
|
||||
#include <openengine/ogre/renderer.hpp>
|
||||
namespace MWRender{
|
||||
class Npcs{
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,16 +1,15 @@
|
||||
#ifndef _GAME_RENDERING_INTERFACE_H
|
||||
#define _GAME_RENDERING_INTERFACE_H
|
||||
namespace MWRender{
|
||||
class Npcs;
|
||||
class Creatures;
|
||||
class Objects;
|
||||
class Actors;
|
||||
class Player;
|
||||
|
||||
class RenderingInterface{
|
||||
public:
|
||||
virtual MWRender::Npcs& getNPCs() = 0;
|
||||
virtual MWRender::Creatures& getCreatures() = 0;
|
||||
virtual MWRender::Objects& getObjects() = 0;
|
||||
virtual MWRender::Player& getPlayer() = 0;
|
||||
virtual MWRender::Actors& getActors() = 0;
|
||||
virtual ~RenderingInterface(){};
|
||||
};
|
||||
}
|
||||
|
@ -1,116 +1,762 @@
|
||||
#include "sky.hpp"
|
||||
#include "Caelum.h"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
//
|
||||
// Implements a Caelum sky with default settings.
|
||||
//
|
||||
// Note: this is intended as a temporary solution to provide some form of
|
||||
// sky rendering. This code will obviously need significant tailoring to
|
||||
// support fidelity with Morrowind's rendering. Before doing major work
|
||||
// on this class, more research should be done to determine whether
|
||||
// Caelum or another plug-in such as SkyX would be best for the long-term.
|
||||
//
|
||||
class CaelumManager : public SkyManager
|
||||
{
|
||||
protected:
|
||||
Caelum::CaelumSystem* mpCaelumSystem;
|
||||
|
||||
public:
|
||||
CaelumManager (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir);
|
||||
virtual ~CaelumManager ();
|
||||
|
||||
virtual void enable() {}
|
||||
|
||||
virtual void disable() {}
|
||||
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreMesh.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreHardwareVertexBuffer.h>
|
||||
#include <OgreHighLevelGpuProgramManager.h>
|
||||
|
||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||
|
||||
using namespace MWRender;
|
||||
using namespace Ogre;
|
||||
|
||||
// the speed at which the clouds are animated
|
||||
#define CLOUD_SPEED 0.001
|
||||
|
||||
// this distance has to be set accordingly so that the
|
||||
// celestial bodies are behind the clouds, but in front of the atmosphere
|
||||
#define CELESTIAL_BODY_DISTANCE 1000.f
|
||||
|
||||
BillboardObject::BillboardObject( const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
init(textureName, initialSize, position, rootNode);
|
||||
}
|
||||
|
||||
BillboardObject::BillboardObject()
|
||||
{
|
||||
}
|
||||
|
||||
void BillboardObject::setVisible(const bool visible)
|
||||
{
|
||||
mNode->setVisible(visible);
|
||||
}
|
||||
|
||||
void BillboardObject::setSize(const float size)
|
||||
{
|
||||
mNode->setScale(size, size, size);
|
||||
}
|
||||
|
||||
void BillboardObject::setVisibility(const float visibility)
|
||||
{
|
||||
mMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, visibility);
|
||||
}
|
||||
|
||||
void BillboardObject::setPosition(const Vector3& pPosition)
|
||||
{
|
||||
Vector3 normalised = pPosition.normalisedCopy();
|
||||
Vector3 finalPosition = normalised * CELESTIAL_BODY_DISTANCE;
|
||||
|
||||
mBBSet->setCommonDirection( -normalised );
|
||||
|
||||
mNode->setPosition(finalPosition);
|
||||
}
|
||||
|
||||
Vector3 BillboardObject::getPosition() const
|
||||
{
|
||||
return mNode->getPosition();
|
||||
}
|
||||
|
||||
void BillboardObject::setColour(const ColourValue& pColour)
|
||||
{
|
||||
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
|
||||
}
|
||||
|
||||
void BillboardObject::setRenderQueue(unsigned int id)
|
||||
{
|
||||
mBBSet->setRenderQueueGroup(id);
|
||||
}
|
||||
|
||||
SceneNode* BillboardObject::getNode()
|
||||
{
|
||||
return mNode;
|
||||
}
|
||||
|
||||
void BillboardObject::init(const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
SceneManager* sceneMgr = rootNode->getCreator();
|
||||
|
||||
virtual void setHour (double hour) {}
|
||||
///< will be called even when sky is disabled.
|
||||
Vector3 finalPosition = position.normalisedCopy() * CELESTIAL_BODY_DISTANCE;
|
||||
|
||||
static unsigned int bodyCount=0;
|
||||
|
||||
/// \todo These billboards are not 100% correct, might want to revisit them later
|
||||
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
|
||||
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
|
||||
mBBSet->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+2);
|
||||
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
|
||||
mBBSet->setCommonDirection( -position.normalisedCopy() );
|
||||
mNode = rootNode->createChildSceneNode();
|
||||
mNode->setPosition(finalPosition);
|
||||
mNode->attachObject(mBBSet);
|
||||
mBBSet->createBillboard(0,0,0);
|
||||
|
||||
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
|
||||
mMaterial->removeAllTechniques();
|
||||
Pass* p = mMaterial->createTechnique()->createPass();
|
||||
p->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
p->setDepthCheckEnabled(false);
|
||||
p->setDepthWriteEnabled(false);
|
||||
p->setSelfIllumination(1.0,1.0,1.0);
|
||||
p->setDiffuse(0.0,0.0,0.0,1.0);
|
||||
p->setAmbient(0.0,0.0,0.0);
|
||||
p->createTextureUnitState(textureName);
|
||||
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
|
||||
|
||||
bodyCount++;
|
||||
}
|
||||
|
||||
Moon::Moon( const String& textureName,
|
||||
const float initialSize,
|
||||
const Vector3& position,
|
||||
SceneNode* rootNode)
|
||||
{
|
||||
init(textureName, initialSize, position, rootNode);
|
||||
|
||||
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||
HighLevelGpuProgramPtr vshader;
|
||||
if (mgr.resourceExists("Moon_VP"))
|
||||
vshader = mgr.getByName("Moon_VP");
|
||||
else
|
||||
vshader = mgr.createProgram("Moon_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM);
|
||||
vshader->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream;
|
||||
outStream <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
vshader->setSource(outStream.str());
|
||||
vshader->load();
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
|
||||
|
||||
HighLevelGpuProgramPtr fshader;
|
||||
if (mgr.resourceExists("Moon_FP"))
|
||||
fshader = mgr.getByName("Moon_FP");
|
||||
else
|
||||
fshader = mgr.createProgram("Moon_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM);
|
||||
|
||||
fshader->setParameter("profiles", "ps_2_x arbfp1");
|
||||
fshader->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream2;
|
||||
outStream2 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform float4 diffuse, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" float4 tex = tex2D(texture, uv); \n"
|
||||
" oColor = float4(emissive.xyz,1) * tex2D(texture, uv) * float4(1,1,1,diffuse.a); \n"
|
||||
"}";
|
||||
fshader->setSource(outStream2.str());
|
||||
fshader->load();
|
||||
fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
|
||||
|
||||
setVisibility(1.0);
|
||||
|
||||
mPhase = Moon::Phase_Full;
|
||||
}
|
||||
|
||||
void Moon::setType(const Moon::Type& type)
|
||||
{
|
||||
mType = type;
|
||||
}
|
||||
|
||||
|
||||
/// \todo the moon phase rendering is not correct - the dark part of the moon does not occlude the stars
|
||||
void Moon::setPhase(const Moon::Phase& phase)
|
||||
{
|
||||
Ogre::String textureName = "textures\\tx_";
|
||||
|
||||
if (mType == Moon::Type_Secunda) textureName += "secunda_";
|
||||
else textureName += "masser_";
|
||||
|
||||
if (phase == Moon::Phase_New) textureName += "new";
|
||||
else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax";
|
||||
else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax";
|
||||
else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax";
|
||||
else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan";
|
||||
else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan";
|
||||
else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan";
|
||||
else if (phase == Moon::Phase_Full) textureName += "full";
|
||||
|
||||
textureName += ".dds";
|
||||
|
||||
mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(textureName);
|
||||
|
||||
mPhase = phase;
|
||||
}
|
||||
|
||||
Moon::Phase Moon::getPhase() const
|
||||
{
|
||||
return mPhase;
|
||||
}
|
||||
|
||||
unsigned int Moon::getPhaseInt() const
|
||||
{
|
||||
if (mPhase == Moon::Phase_New) return 0;
|
||||
else if (mPhase == Moon::Phase_WaxingCrescent) return 1;
|
||||
else if (mPhase == Moon::Phase_WaningCrescent) return 1;
|
||||
else if (mPhase == Moon::Phase_WaxingHalf) return 2;
|
||||
else if (mPhase == Moon::Phase_WaningHalf) return 2;
|
||||
else if (mPhase == Moon::Phase_WaxingGibbous) return 3;
|
||||
else if (mPhase == Moon::Phase_WaningGibbous) return 3;
|
||||
else if (mPhase == Moon::Phase_Full) return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType)
|
||||
{
|
||||
// Get the vertex colour buffer of this mesh
|
||||
const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE );
|
||||
HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource());
|
||||
|
||||
// Lock
|
||||
void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL);
|
||||
|
||||
// Iterate over all vertices
|
||||
int vertex_size = colourBuffer->getVertexSize();
|
||||
float * currentVertex = NULL;
|
||||
for (unsigned int i=0; i<colourBuffer->getNumVertices(); ++i)
|
||||
{
|
||||
// Get a pointer to the vertex colour
|
||||
ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex );
|
||||
|
||||
virtual void setDate (int day, int month) {}
|
||||
///< will be called even when sky is disabled.
|
||||
unsigned char alpha;
|
||||
if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row
|
||||
else if (meshType == 1)
|
||||
{
|
||||
if (i>= 49 && i <= 64) alpha = 0; // bottom-most row
|
||||
else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row
|
||||
else alpha = 255;
|
||||
}
|
||||
|
||||
virtual int getMasserPhase() const { return 0; }
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
uint8 tmpR = static_cast<uint8>(255);
|
||||
uint8 tmpG = static_cast<uint8>(255);
|
||||
uint8 tmpB = static_cast<uint8>(255);
|
||||
uint8 tmpA = static_cast<uint8>(alpha);
|
||||
|
||||
virtual int getSecundaPhase() const { return 0; }
|
||||
///< 0 new moon, 1 waxing or waning cresecent, 2 waxing or waning half,
|
||||
/// 3 waxing or waning gibbous, 4 full moon
|
||||
// This does not matter since R and B are always 1.
|
||||
/*VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType();
|
||||
switch (format)
|
||||
{
|
||||
case VET_COLOUR_ARGB:
|
||||
std::swap(tmpR, tmpB);
|
||||
break;
|
||||
case VET_COLOUR_ABGR:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}*/
|
||||
|
||||
// Modify
|
||||
*((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
|
||||
|
||||
virtual void setMoonColour (bool red) {}
|
||||
};
|
||||
// Move to the next vertex
|
||||
pData+=vertex_size;
|
||||
}
|
||||
|
||||
// Unlock
|
||||
ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock();
|
||||
}
|
||||
|
||||
SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) :
|
||||
mGlareFade(0), mGlareEnabled(false)
|
||||
{
|
||||
mViewport = pCamera->getViewport();
|
||||
mSceneMgr = pMwRoot->getCreator();
|
||||
mRootNode = pCamera->getParentSceneNode()->createChildSceneNode();
|
||||
mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates
|
||||
mRootNode->setInheritOrientation(false);
|
||||
|
||||
/// \todo preload all the textures and meshes that are used for sky rendering
|
||||
|
||||
// Create overlay used for thunderstorm
|
||||
MaterialPtr material = MaterialManager::getSingleton().create( "ThunderMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );
|
||||
Pass* pass = material->getTechnique(0)->getPass(0);
|
||||
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
mThunderTextureUnit = pass->createTextureUnitState();
|
||||
mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); // always black colour
|
||||
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f);
|
||||
OverlayManager& ovm = OverlayManager::getSingleton();
|
||||
mThunderOverlay = ovm.create( "ThunderOverlay" );
|
||||
OverlayContainer* overlay_panel;
|
||||
overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "ThunderPanel");
|
||||
overlay_panel->_setPosition(0, 0);
|
||||
overlay_panel->_setDimensions(1, 1);
|
||||
overlay_panel->setMaterialName( "ThunderMaterial" );
|
||||
overlay_panel->show();
|
||||
mThunderOverlay->add2D(overlay_panel);
|
||||
mThunderOverlay->hide();
|
||||
|
||||
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||
mSecunda->setType(Moon::Type_Secunda);
|
||||
mSecunda->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+4);
|
||||
|
||||
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
|
||||
mMasser->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+3);
|
||||
mMasser->setType(Moon::Type_Masser);
|
||||
|
||||
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
|
||||
mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE);
|
||||
|
||||
CaelumManager::CaelumManager (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir)
|
||||
: mpCaelumSystem (NULL)
|
||||
|
||||
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
|
||||
|
||||
// Stars
|
||||
/// \todo sky_night_02.nif (available in Bloodmoon)
|
||||
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
|
||||
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
|
||||
night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1);
|
||||
|
||||
mAtmosphereNight = mRootNode->createChildSceneNode();
|
||||
mAtmosphereNight->attachObject(night1_ent);
|
||||
|
||||
for (unsigned int i=0; i<night1_ent->getNumSubEntities(); ++i)
|
||||
{
|
||||
using namespace Ogre;
|
||||
using namespace Caelum;
|
||||
|
||||
assert(pCamera);
|
||||
assert(pRenderWindow);
|
||||
|
||||
// Load the Caelum resources
|
||||
//
|
||||
ResourceGroupManager::getSingleton().addResourceLocation((resDir / "caelum").string(), "FileSystem", "Caelum");
|
||||
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
||||
|
||||
// Load the Caelum resources
|
||||
//
|
||||
Ogre::SceneManager* pScene = pCamera->getSceneManager();
|
||||
Caelum::CaelumSystem::CaelumComponent componentMask = CaelumSystem::CAELUM_COMPONENTS_DEFAULT;
|
||||
mpCaelumSystem = new Caelum::CaelumSystem (Root::getSingletonPtr(), pScene, componentMask);
|
||||
MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial();
|
||||
mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
|
||||
mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0);
|
||||
mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false);
|
||||
mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
|
||||
// Set time acceleration.
|
||||
mpCaelumSystem->getUniversalClock()->setTimeScale(128);
|
||||
mStarsMaterials[i] = mp;
|
||||
}
|
||||
|
||||
// Stars vertex shader
|
||||
HighLevelGpuProgramPtr vshader3 = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
vshader3->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader3->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream4;
|
||||
outStream4 <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float oFade : TEXCOORD1, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oFade = (position.z > 50) ? 1.f : 0.f; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
vshader3->setSource(outStream4.str());
|
||||
vshader3->load();
|
||||
vshader3->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setVertexProgram(vshader3->getName());
|
||||
|
||||
// Stars fragment shader
|
||||
HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_FRAGMENT_PROGRAM);
|
||||
stars_fp->setParameter("profiles", "ps_2_x arbfp1");
|
||||
stars_fp->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream5;
|
||||
outStream5 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" in float fade : TEXCOORD1, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform float opacity, \n"
|
||||
" uniform float4 diffuse, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"
|
||||
"}";
|
||||
stars_fp->setSource(outStream5.str());
|
||||
stars_fp->load();
|
||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
|
||||
night1_ent->getSubEntity(3)->getMaterial()->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName());
|
||||
|
||||
// Atmosphere (day)
|
||||
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
|
||||
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
|
||||
|
||||
ModVertexAlpha(atmosphere_ent, 0);
|
||||
|
||||
atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY);
|
||||
mAtmosphereDay = mRootNode->createChildSceneNode();
|
||||
mAtmosphereDay->attachObject(atmosphere_ent);
|
||||
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
|
||||
|
||||
// Atmosphere shader
|
||||
HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
|
||||
// Disable fog since OpenMW is handling OGRE fog elsewhere
|
||||
mpCaelumSystem->setManageSceneFog(false);
|
||||
vshader->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader->setParameter("entry_point", "main_vp");
|
||||
|
||||
StringUtil::StrStreamType outStream;
|
||||
outStream <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float4 color : COLOR, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" uniform float4 emissive, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
" oColor = color * emissive; \n"
|
||||
"}";
|
||||
vshader->setSource(outStream.str());
|
||||
vshader->load();
|
||||
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
vshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
|
||||
|
||||
// Change the camera far distance to make sure the sky is not clipped
|
||||
pCamera->setFarClipDistance(50000);
|
||||
// Clouds
|
||||
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
|
||||
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
|
||||
clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5);
|
||||
SceneNode* clouds_node = mRootNode->createChildSceneNode();
|
||||
clouds_node->attachObject(clouds_ent);
|
||||
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
|
||||
|
||||
// Clouds vertex shader
|
||||
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_VERTEX_PROGRAM);
|
||||
vshader2->setParameter("profiles", "vs_2_x arbvp1");
|
||||
vshader2->setParameter("entry_point", "main_vp");
|
||||
StringUtil::StrStreamType outStream3;
|
||||
outStream3 <<
|
||||
"void main_vp( \n"
|
||||
" float4 position : POSITION, \n"
|
||||
" in float4 color : COLOR, \n"
|
||||
" out float4 oColor : TEXCOORD1, \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float2 oUV : TEXCOORD0, \n"
|
||||
" out float4 oPosition : POSITION, \n"
|
||||
" uniform float4x4 worldViewProj \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" oUV = uv; \n"
|
||||
" oColor = color; \n"
|
||||
" oPosition = mul( worldViewProj, position ); \n"
|
||||
"}";
|
||||
vshader2->setSource(outStream3.str());
|
||||
vshader2->load();
|
||||
vshader2->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName());
|
||||
|
||||
// Clouds fragment shader
|
||||
mCloudFragmentShader = mgr.createProgram("Clouds_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
"cg", GPT_FRAGMENT_PROGRAM);
|
||||
mCloudFragmentShader->setParameter("profiles", "ps_2_x arbfp1");
|
||||
mCloudFragmentShader->setParameter("entry_point", "main_fp");
|
||||
StringUtil::StrStreamType outStream2;
|
||||
outStream2 <<
|
||||
"void main_fp( \n"
|
||||
" in float2 uv : TEXCOORD0, \n"
|
||||
" out float4 oColor : COLOR, \n"
|
||||
" in float4 color : TEXCOORD1, \n"
|
||||
" uniform sampler2D texture : TEXUNIT0, \n"
|
||||
" uniform sampler2D secondTexture : TEXUNIT1, \n"
|
||||
" uniform float transitionFactor, \n"
|
||||
" uniform float time, \n"
|
||||
" uniform float speed, \n"
|
||||
" uniform float opacity, \n"
|
||||
" uniform float4 emissive \n"
|
||||
") \n"
|
||||
"{ \n"
|
||||
" uv += float2(1,1) * time * speed * "<<CLOUD_SPEED<<"; \n" // Scroll in x,y direction
|
||||
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
|
||||
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"
|
||||
"}";
|
||||
mCloudFragmentShader->setSource(outStream2.str());
|
||||
mCloudFragmentShader->load();
|
||||
mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName());
|
||||
setCloudsOpacity(0.75);
|
||||
|
||||
ModVertexAlpha(clouds_ent, 1);
|
||||
|
||||
// I'm not sure if the materials are being used by any other objects
|
||||
// Make a unique "modifiable" copy of the materials to be sure
|
||||
mCloudMaterial = mCloudMaterial->clone("Clouds");
|
||||
clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial);
|
||||
mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere");
|
||||
atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial);
|
||||
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false);
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
|
||||
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
|
||||
}
|
||||
|
||||
// Register Caelum as an OGRE listener
|
||||
pRenderWindow->addListener(mpCaelumSystem);
|
||||
Root::getSingletonPtr()->addFrameListener(mpCaelumSystem);
|
||||
}
|
||||
SkyManager::~SkyManager()
|
||||
{
|
||||
delete mSun;
|
||||
delete mSunGlare;
|
||||
delete mMasser;
|
||||
delete mSecunda;
|
||||
}
|
||||
|
||||
CaelumManager::~CaelumManager()
|
||||
{
|
||||
if (mpCaelumSystem)
|
||||
mpCaelumSystem->shutdown (false);
|
||||
}
|
||||
int SkyManager::getMasserPhase() const
|
||||
{
|
||||
return mMasser->getPhaseInt();
|
||||
}
|
||||
|
||||
/// Creates and connects the sky rendering component to OGRE.
|
||||
///
|
||||
/// \return NULL on failure.
|
||||
///
|
||||
SkyManager* SkyManager::create (Ogre::RenderWindow* pRenderWindow,
|
||||
Ogre::Camera* pCamera,
|
||||
const boost::filesystem::path& resDir)
|
||||
{
|
||||
SkyManager* pSkyManager = NULL;
|
||||
int SkyManager::getSecundaPhase() const
|
||||
{
|
||||
return mSecunda->getPhaseInt();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
pSkyManager = new CaelumManager(pRenderWindow, pCamera, resDir);
|
||||
}
|
||||
catch (Ogre::Exception& e)
|
||||
void SkyManager::update(float duration)
|
||||
{
|
||||
if (!mEnabled) return;
|
||||
|
||||
// UV Scroll the clouds
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", 1);
|
||||
|
||||
/// \todo improve this
|
||||
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
|
||||
// increase the strength of the sun glare effect depending
|
||||
// on how directly the player is looking at the sun
|
||||
if (mSunEnabled)
|
||||
{
|
||||
Vector3 sun = mSunGlare->getPosition();
|
||||
sun = Vector3(sun.x, sun.z, -sun.y);
|
||||
Vector3 cam = mViewport->getCamera()->getRealDirection();
|
||||
const Degree angle = sun.angleBetween( cam );
|
||||
float val = 1- (angle.valueDegrees() / 180.f);
|
||||
val = (val*val*val*val)*2;
|
||||
|
||||
if (mGlareEnabled)
|
||||
{
|
||||
std::cout << "\nOGRE Exception when attempting to add sky: "
|
||||
<< e.getFullDescription().c_str() << std::endl;
|
||||
mGlareFade += duration*3;
|
||||
if (mGlareFade > 1) mGlareFade = 1;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
else
|
||||
{
|
||||
std::cout << "\nException when attempting to add sky: "
|
||||
<< e.what() << std::endl;
|
||||
mGlareFade -= duration*3;
|
||||
if (mGlareFade < 0.3) mGlareFade = 0;
|
||||
}
|
||||
|
||||
mSunGlare->setSize(val * (mGlareFade));
|
||||
}
|
||||
|
||||
mSunGlare->setVisible(mGlareFade>0 && mSunEnabled);
|
||||
mSun->setVisible(mSunEnabled);
|
||||
mMasser->setVisible(mMasserEnabled);
|
||||
mSecunda->setVisible(mSecundaEnabled);
|
||||
}
|
||||
|
||||
void SkyManager::enable()
|
||||
{
|
||||
mRootNode->setVisible(true);
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::disable()
|
||||
{
|
||||
mRootNode->setVisible(false);
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setMoonColour (bool red)
|
||||
{
|
||||
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
|
||||
: ColourValue(1.0, 1.0, 1.0));
|
||||
}
|
||||
|
||||
void SkyManager::setCloudsOpacity(float opacity)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity));
|
||||
}
|
||||
|
||||
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
||||
{
|
||||
if (mClouds != weather.mCloudTexture)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture);
|
||||
mClouds = weather.mCloudTexture;
|
||||
}
|
||||
|
||||
if (mNextClouds != weather.mNextCloudTexture)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("textures\\"+weather.mNextCloudTexture);
|
||||
mNextClouds = weather.mNextCloudTexture;
|
||||
}
|
||||
|
||||
if (mCloudBlendFactor != weather.mCloudBlendFactor)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("transitionFactor", Real(weather.mCloudBlendFactor));
|
||||
mCloudBlendFactor = weather.mCloudBlendFactor;
|
||||
}
|
||||
|
||||
if (mCloudOpacity != weather.mCloudOpacity)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(weather.mCloudOpacity));
|
||||
mCloudOpacity = weather.mCloudOpacity;
|
||||
}
|
||||
|
||||
if (mCloudColour != weather.mSunColor)
|
||||
{
|
||||
ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7,
|
||||
weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7,
|
||||
weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7);
|
||||
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(clr);
|
||||
mCloudColour = weather.mSunColor;
|
||||
}
|
||||
|
||||
if (mSkyColour != weather.mSkyColor)
|
||||
{
|
||||
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor);
|
||||
mSkyColour = weather.mSkyColor;
|
||||
}
|
||||
|
||||
if (mCloudSpeed != weather.mCloudSpeed)
|
||||
{
|
||||
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("speed", Real(weather.mCloudSpeed));
|
||||
mCloudSpeed = weather.mCloudSpeed;
|
||||
}
|
||||
|
||||
if (weather.mNight && mStarsOpacity != weather.mNightFade)
|
||||
{
|
||||
for (int i=0; i<7; ++i)
|
||||
mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade);
|
||||
mStarsOpacity = weather.mNightFade;
|
||||
}
|
||||
|
||||
float strength;
|
||||
float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length());
|
||||
if (timeofday_angle <= 0.44)
|
||||
strength = timeofday_angle/0.44f;
|
||||
else
|
||||
strength = 1.f;
|
||||
|
||||
mSunGlare->setVisibility(weather.mGlareView * strength);
|
||||
|
||||
mAtmosphereNight->setVisible(weather.mNight && mEnabled);
|
||||
}
|
||||
|
||||
return pSkyManager;
|
||||
void SkyManager::setGlare(bool glare)
|
||||
{
|
||||
mGlareEnabled = glare;
|
||||
}
|
||||
|
||||
Vector3 SkyManager::getRealSunPos()
|
||||
{
|
||||
return mSun->getNode()->_getDerivedPosition();
|
||||
}
|
||||
|
||||
void SkyManager::sunEnable()
|
||||
{
|
||||
mSunEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::sunDisable()
|
||||
{
|
||||
mSunEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setSunDirection(const Vector3& direction)
|
||||
{
|
||||
mSun->setPosition(direction);
|
||||
mSunGlare->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::setMasserDirection(const Vector3& direction)
|
||||
{
|
||||
mMasser->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::setSecundaDirection(const Vector3& direction)
|
||||
{
|
||||
mSecunda->setPosition(direction);
|
||||
}
|
||||
|
||||
void SkyManager::masserEnable()
|
||||
{
|
||||
mMasserEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::secundaEnable()
|
||||
{
|
||||
mSecundaEnabled = true;
|
||||
}
|
||||
|
||||
void SkyManager::masserDisable()
|
||||
{
|
||||
mMasserEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::secundaDisable()
|
||||
{
|
||||
mSecundaEnabled = false;
|
||||
}
|
||||
|
||||
void SkyManager::setThunder(const float factor)
|
||||
{
|
||||
if (factor > 0.f)
|
||||
{
|
||||
mThunderOverlay->show();
|
||||
mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, factor*0.6);
|
||||
}
|
||||
}
|
||||
else
|
||||
mThunderOverlay->hide();
|
||||
}
|
||||
|
||||
void SkyManager::setMasserFade(const float fade)
|
||||
{
|
||||
mMasser->setVisibility(fade);
|
||||
}
|
||||
|
||||
void SkyManager::setSecundaFade(const float fade)
|
||||
{
|
||||
mSecunda->setVisibility(fade);
|
||||
}
|
||||
|
||||
void SkyManager::setHour(double hour)
|
||||
{
|
||||
mHour = hour;
|
||||
}
|
||||
|
||||
void SkyManager::setDate(int day, int month)
|
||||
{
|
||||
mDay = day;
|
||||
mMonth = month;
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
|
||||
#include "animationextensions.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
#include <components/interpreter/interpreter.hpp>
|
||||
#include <components/interpreter/runtime.hpp>
|
||||
#include <components/interpreter/opcodes.hpp>
|
||||
|
||||
#include "../mwworld/world.hpp"
|
||||
|
||||
#include "interpretercontext.hpp"
|
||||
#include "ref.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
namespace Animation
|
||||
{
|
||||
template<class R>
|
||||
class OpSkipAnim : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
context.getWorld().skipAnimation (ptr);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpPlayAnim : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string group = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Integer mode = 0;
|
||||
|
||||
if (arg0==1)
|
||||
{
|
||||
mode = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (mode<0 || mode>2)
|
||||
throw std::runtime_error ("animation mode out of range");
|
||||
}
|
||||
|
||||
context.getWorld().playAnimationGroup (ptr, group, mode, 1);
|
||||
}
|
||||
};
|
||||
|
||||
template<class R>
|
||||
class OpLoopAnim : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
InterpreterContext& context =
|
||||
static_cast<InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string group = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
Interpreter::Type_Integer loops = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (loops<0)
|
||||
throw std::runtime_error ("number of animation loops must be non-negative");
|
||||
|
||||
Interpreter::Type_Integer mode = 0;
|
||||
|
||||
if (arg0==1)
|
||||
{
|
||||
mode = runtime[0].mInteger;
|
||||
runtime.pop();
|
||||
|
||||
if (mode<0 || mode>2)
|
||||
throw std::runtime_error ("animation mode out of range");
|
||||
}
|
||||
|
||||
context.getWorld().playAnimationGroup (ptr, group, mode, loops);
|
||||
}
|
||||
};
|
||||
|
||||
const int opcodeSkipAnim = 0x2000138;
|
||||
const int opcodeSkipAnimExplicit = 0x2000139;
|
||||
const int opcodePlayAnim = 0x20006;
|
||||
const int opcodePlayAnimExplicit = 0x20007;
|
||||
const int opcodeLoopAnim = 0x20008;
|
||||
const int opcodeLoopAnimExplicit = 0x20009;
|
||||
|
||||
void registerExtensions (Compiler::Extensions& extensions)
|
||||
{
|
||||
extensions.registerInstruction ("skipanim", "", opcodeSkipAnim, opcodeSkipAnimExplicit);
|
||||
extensions.registerInstruction ("playgroup", "c/l", opcodePlayAnim, opcodePlayAnimExplicit);
|
||||
extensions.registerInstruction ("loopgroup", "cl/l", opcodeLoopAnim, opcodeLoopAnimExplicit);
|
||||
}
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (opcodeSkipAnim, new OpSkipAnim<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeSkipAnimExplicit, new OpSkipAnim<ExplicitRef>);
|
||||
interpreter.installSegment3 (opcodePlayAnim, new OpPlayAnim<ImplicitRef>);
|
||||
interpreter.installSegment3 (opcodePlayAnimExplicit, new OpPlayAnim<ExplicitRef>);
|
||||
interpreter.installSegment3 (opcodeLoopAnim, new OpLoopAnim<ImplicitRef>);
|
||||
interpreter.installSegment3 (opcodeLoopAnimExplicit, new OpLoopAnim<ExplicitRef>);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
#ifndef GAME_SCRIPT_ANIMATIONEXTENSIONS_H
|
||||
#define GAME_SCRIPT_ANIMATIONEXTENSIONS_H
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Extensions;
|
||||
}
|
||||
|
||||
namespace Interpreter
|
||||
{
|
||||
class Interpreter;
|
||||
}
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
namespace Animation
|
||||
{
|
||||
void registerExtensions (Compiler::Extensions& extensions);
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,342 @@
|
||||
|
||||
#include "containerstore.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdexcept>
|
||||
|
||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::begin (int mask)
|
||||
{
|
||||
return ContainerStoreIterator (mask, this);
|
||||
}
|
||||
|
||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
|
||||
{
|
||||
return ContainerStoreIterator (this);
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStore::add (const Ptr& ptr)
|
||||
{
|
||||
/// \todo implement item stocking
|
||||
|
||||
switch (getType (ptr))
|
||||
{
|
||||
case Type_Potion: potions.list.push_back (*ptr.get<ESM::Potion>()); break;
|
||||
case Type_Apparatus: appas.list.push_back (*ptr.get<ESM::Apparatus>()); break;
|
||||
case Type_Armor: armors.list.push_back (*ptr.get<ESM::Armor>()); break;
|
||||
case Type_Book: books.list.push_back (*ptr.get<ESM::Book>()); break;
|
||||
case Type_Clothing: clothes.list.push_back (*ptr.get<ESM::Clothing>()); break;
|
||||
case Type_Ingredient: ingreds.list.push_back (*ptr.get<ESM::Ingredient>()); break;
|
||||
case Type_Light: lights.list.push_back (*ptr.get<ESM::Light>()); break;
|
||||
case Type_Lockpick: lockpicks.list.push_back (*ptr.get<ESM::Tool>()); break;
|
||||
case Type_Miscellaneous: miscItems.list.push_back (*ptr.get<ESM::Miscellaneous>()); break;
|
||||
case Type_Probe: probes.list.push_back (*ptr.get<ESM::Probe>()); break;
|
||||
case Type_Repair: repairs.list.push_back (*ptr.get<ESM::Repair>()); break;
|
||||
case Type_Weapon: weapons.list.push_back (*ptr.get<ESM::Weapon>()); break;
|
||||
}
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStore::getType (const Ptr& ptr)
|
||||
{
|
||||
if (ptr.isEmpty())
|
||||
throw std::runtime_error ("can't put a non-existent object into a container");
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Potion).name())
|
||||
return Type_Potion;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Apparatus).name())
|
||||
return Type_Apparatus;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Armor).name())
|
||||
return Type_Armor;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Book).name())
|
||||
return Type_Book;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Clothing).name())
|
||||
return Type_Clothing;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Ingredient).name())
|
||||
return Type_Ingredient;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Light).name())
|
||||
return Type_Light;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Tool).name())
|
||||
return Type_Lockpick;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Miscellaneous).name())
|
||||
return Type_Miscellaneous;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Probe).name())
|
||||
return Type_Probe;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Repair).name())
|
||||
return Type_Repair;
|
||||
|
||||
if (ptr.getTypeName()==typeid (ESM::Weapon).name())
|
||||
return Type_Weapon;
|
||||
|
||||
throw std::runtime_error (
|
||||
"Object of type " + ptr.getTypeName() + " can not be placed into a container");
|
||||
}
|
||||
|
||||
|
||||
MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container)
|
||||
: mType (-1), mMask (0), mContainer (container)
|
||||
{}
|
||||
|
||||
MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStore *container)
|
||||
: mType (0), mMask (mask), mContainer (container)
|
||||
{
|
||||
nextType();
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStoreIterator::incType()
|
||||
{
|
||||
if (mType==0)
|
||||
mType = 1;
|
||||
else if (mType!=-1)
|
||||
{
|
||||
mType <<= 1;
|
||||
|
||||
if (mType>ContainerStore::Type_Last)
|
||||
mType = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void MWWorld::ContainerStoreIterator::nextType()
|
||||
{
|
||||
while (mType!=-1)
|
||||
{
|
||||
incType();
|
||||
|
||||
if (mType & mMask)
|
||||
if (resetIterator())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MWWorld::ContainerStoreIterator::resetIterator()
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case ContainerStore::Type_Potion:
|
||||
|
||||
mPotion = mContainer->potions.list.begin();
|
||||
return mPotion!=mContainer->potions.list.end();
|
||||
|
||||
case ContainerStore::Type_Apparatus:
|
||||
|
||||
mApparatus = mContainer->appas.list.begin();
|
||||
return mApparatus!=mContainer->appas.list.end();
|
||||
|
||||
case ContainerStore::Type_Armor:
|
||||
|
||||
mArmor = mContainer->armors.list.begin();
|
||||
return mArmor!=mContainer->armors.list.end();
|
||||
|
||||
case ContainerStore::Type_Book:
|
||||
|
||||
mBook = mContainer->books.list.begin();
|
||||
return mBook!=mContainer->books.list.end();
|
||||
|
||||
case ContainerStore::Type_Clothing:
|
||||
|
||||
mClothing = mContainer->clothes.list.begin();
|
||||
return mClothing!=mContainer->clothes.list.end();
|
||||
|
||||
case ContainerStore::Type_Ingredient:
|
||||
|
||||
mIngredient = mContainer->ingreds.list.begin();
|
||||
return mIngredient!=mContainer->ingreds.list.end();
|
||||
|
||||
case ContainerStore::Type_Light:
|
||||
|
||||
mLight = mContainer->lights.list.begin();
|
||||
return mLight!=mContainer->lights.list.end();
|
||||
|
||||
case ContainerStore::Type_Lockpick:
|
||||
|
||||
mLockpick = mContainer->lockpicks.list.begin();
|
||||
return mLockpick!=mContainer->lockpicks.list.end();
|
||||
|
||||
case ContainerStore::Type_Miscellaneous:
|
||||
|
||||
mMiscellaneous = mContainer->miscItems.list.begin();
|
||||
return mMiscellaneous!=mContainer->miscItems.list.end();
|
||||
|
||||
case ContainerStore::Type_Probe:
|
||||
|
||||
mProbe = mContainer->probes.list.begin();
|
||||
return mProbe!=mContainer->probes.list.end();
|
||||
|
||||
case ContainerStore::Type_Repair:
|
||||
|
||||
mRepair = mContainer->repairs.list.begin();
|
||||
return mRepair!=mContainer->repairs.list.end();
|
||||
|
||||
case ContainerStore::Type_Weapon:
|
||||
|
||||
mWeapon = mContainer->weapons.list.begin();
|
||||
return mWeapon!=mContainer->weapons.list.end();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWWorld::ContainerStoreIterator::incIterator()
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case ContainerStore::Type_Potion:
|
||||
|
||||
++mPotion;
|
||||
return mPotion==mContainer->potions.list.end();
|
||||
|
||||
case ContainerStore::Type_Apparatus:
|
||||
|
||||
++mApparatus;
|
||||
return mApparatus==mContainer->appas.list.end();
|
||||
|
||||
case ContainerStore::Type_Armor:
|
||||
|
||||
++mArmor;
|
||||
return mArmor==mContainer->armors.list.end();
|
||||
|
||||
case ContainerStore::Type_Book:
|
||||
|
||||
++mBook;
|
||||
return mBook==mContainer->books.list.end();
|
||||
|
||||
case ContainerStore::Type_Clothing:
|
||||
|
||||
++mClothing;
|
||||
return mClothing==mContainer->clothes.list.end();
|
||||
|
||||
case ContainerStore::Type_Ingredient:
|
||||
|
||||
++mIngredient;
|
||||
return mIngredient==mContainer->ingreds.list.end();
|
||||
|
||||
case ContainerStore::Type_Light:
|
||||
|
||||
++mLight;
|
||||
return mLight==mContainer->lights.list.end();
|
||||
|
||||
case ContainerStore::Type_Lockpick:
|
||||
|
||||
++mLockpick;
|
||||
return mLockpick==mContainer->lockpicks.list.end();
|
||||
|
||||
case ContainerStore::Type_Miscellaneous:
|
||||
|
||||
++mMiscellaneous;
|
||||
return mMiscellaneous==mContainer->miscItems.list.end();
|
||||
|
||||
case ContainerStore::Type_Probe:
|
||||
|
||||
++mProbe;
|
||||
return mProbe==mContainer->probes.list.end();
|
||||
|
||||
case ContainerStore::Type_Repair:
|
||||
|
||||
++mRepair;
|
||||
return mRepair==mContainer->repairs.list.end();
|
||||
|
||||
case ContainerStore::Type_Weapon:
|
||||
|
||||
++mWeapon;
|
||||
return mWeapon==mContainer->weapons.list.end();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MWWorld::Ptr *MWWorld::ContainerStoreIterator::operator->() const
|
||||
{
|
||||
mPtr = **this;
|
||||
return &mPtr;
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWWorld::ContainerStoreIterator::operator*() const
|
||||
{
|
||||
switch (mType)
|
||||
{
|
||||
case ContainerStore::Type_Potion: return MWWorld::Ptr (&*mPotion, 0);
|
||||
case ContainerStore::Type_Apparatus: return MWWorld::Ptr (&*mApparatus, 0);
|
||||
case ContainerStore::Type_Armor: return MWWorld::Ptr (&*mArmor, 0);
|
||||
case ContainerStore::Type_Book: return MWWorld::Ptr (&*mBook, 0);
|
||||
case ContainerStore::Type_Clothing: return MWWorld::Ptr (&*mClothing, 0);
|
||||
case ContainerStore::Type_Ingredient: return MWWorld::Ptr (&*mIngredient, 0);
|
||||
case ContainerStore::Type_Light: return MWWorld::Ptr (&*mLight, 0);
|
||||
case ContainerStore::Type_Lockpick: return MWWorld::Ptr (&*mLockpick, 0);
|
||||
case ContainerStore::Type_Miscellaneous: return MWWorld::Ptr (&*mMiscellaneous, 0);
|
||||
case ContainerStore::Type_Probe: return MWWorld::Ptr (&*mProbe, 0);
|
||||
case ContainerStore::Type_Repair: return MWWorld::Ptr (&*mRepair, 0);
|
||||
case ContainerStore::Type_Weapon: return MWWorld::Ptr (&*mWeapon, 0);
|
||||
}
|
||||
|
||||
throw std::runtime_error ("invalid pointer");
|
||||
}
|
||||
|
||||
MWWorld::ContainerStoreIterator& MWWorld::ContainerStoreIterator::operator++()
|
||||
{
|
||||
do
|
||||
{
|
||||
if (incIterator())
|
||||
nextType();
|
||||
}
|
||||
while (mType!=-1 && !(**this).getRefData().getCount());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStoreIterator::operator++ (int)
|
||||
{
|
||||
ContainerStoreIterator iter (*this);
|
||||
++*this;
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool MWWorld::ContainerStoreIterator::isEqual (const ContainerStoreIterator& iter) const
|
||||
{
|
||||
assert (mContainer==iter.mContainer);
|
||||
|
||||
if (mType!=iter.mType)
|
||||
return false;
|
||||
|
||||
switch (mType)
|
||||
{
|
||||
case ContainerStore::Type_Potion: return mPotion==iter.mPotion;
|
||||
case ContainerStore::Type_Apparatus: return mApparatus==iter.mApparatus;
|
||||
case ContainerStore::Type_Armor: return mArmor==iter.mArmor;
|
||||
case ContainerStore::Type_Book: return mBook==iter.mBook;
|
||||
case ContainerStore::Type_Clothing: return mClothing==iter.mClothing;
|
||||
case ContainerStore::Type_Ingredient: return mIngredient==iter.mIngredient;
|
||||
case ContainerStore::Type_Light: return mLight==iter.mLight;
|
||||
case ContainerStore::Type_Lockpick: return mLockpick==iter.mLockpick;
|
||||
case ContainerStore::Type_Miscellaneous: return mMiscellaneous==iter.mMiscellaneous;
|
||||
case ContainerStore::Type_Probe: return mProbe==iter.mProbe;
|
||||
case ContainerStore::Type_Repair: return mRepair==iter.mRepair;
|
||||
case ContainerStore::Type_Weapon: return mWeapon==iter.mWeapon;
|
||||
case -1: return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int MWWorld::ContainerStoreIterator::getType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
bool MWWorld::operator== (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
|
||||
{
|
||||
return left.isEqual (right);
|
||||
}
|
||||
|
||||
bool MWWorld::operator!= (const ContainerStoreIterator& left, const ContainerStoreIterator& right)
|
||||
{
|
||||
return !(left==right);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
|
||||
#include "containerutil.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void listItemsInContainerImp (const std::string& id,
|
||||
ESMS::CellRefList<T, MWWorld::RefData>& containerStore,
|
||||
const ESMS::RecListT<T>& store, std::vector<MWWorld::Ptr>& list)
|
||||
{
|
||||
if (const T *record = store.search (id))
|
||||
{
|
||||
for (typename ESMS::CellRefList<T, MWWorld::RefData>::List::iterator iter
|
||||
(containerStore.list.begin());
|
||||
iter!=containerStore.list.end(); ++iter)
|
||||
{
|
||||
if (iter->base==record)
|
||||
list.push_back (MWWorld::Ptr (&*iter, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
void listItemsInContainer (const std::string& id,
|
||||
ContainerStore<MWWorld::RefData>& containerStore,
|
||||
const ESMS::ESMStore& store, std::vector<Ptr>& list)
|
||||
{
|
||||
listItemsInContainerImp (id, containerStore.potions, store.potions, list);
|
||||
listItemsInContainerImp (id, containerStore.appas, store.appas, list);
|
||||
listItemsInContainerImp (id, containerStore.armors, store.armors, list);
|
||||
listItemsInContainerImp (id, containerStore.books, store.books, list);
|
||||
listItemsInContainerImp (id, containerStore.clothes, store.clothes, list);
|
||||
listItemsInContainerImp (id, containerStore.ingreds, store.ingreds, list);
|
||||
listItemsInContainerImp (id, containerStore.lights, store.lights, list);
|
||||
listItemsInContainerImp (id, containerStore.lockpicks, store.lockpicks, list);
|
||||
listItemsInContainerImp (id, containerStore.miscItems, store.miscItems, list);
|
||||
listItemsInContainerImp (id, containerStore.probes, store.probes, list);
|
||||
listItemsInContainerImp (id, containerStore.repairs, store.repairs, list);
|
||||
listItemsInContainerImp (id, containerStore.weapons, store.weapons, list);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#ifndef GAME_MWWORLD_CONTAINERUTIL_H
|
||||
#define GAME_MWWORLD_CONTAINERUTIL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
#include "containerstore.hpp"
|
||||
#include "ptr.hpp"
|
||||
#include "refdata.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
void listItemsInContainer (const std::string& id, ContainerStore<MWWorld::RefData>& containerStore,
|
||||
const ESMS::ESMStore& store, std::vector<Ptr>& list);
|
||||
///< append all references with the given id to list.
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#ifndef GAME_MWWORLD_CUSTOMDATA_H
|
||||
#define GAME_MWWORLD_CUSTOMDATA_H
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
/// \brief Base class for the MW-class-specific part of RefData
|
||||
class CustomData
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CustomData() {}
|
||||
|
||||
virtual CustomData *clone() const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue