From 6d346933db21946c68ab96b1105b1ea6f61f9b8e Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 10 Mar 2012 17:45:34 -0500 Subject: [PATCH 001/185] gus's changes --- apps/openmw/mwworld/weather.cpp | 8 ++++++++ apps/openmw/mwworld/weather.hpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 059b0ec1e..90afc4e78 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -21,6 +21,14 @@ const std::string WeatherGlobals::mThunderSoundID0 = "Thunder0"; const std::string WeatherGlobals::mThunderSoundID1 = "Thunder1"; const std::string WeatherGlobals::mThunderSoundID2 = "Thunder2"; const std::string WeatherGlobals::mThunderSoundID3 = "Thunder3"; +const float WeatherGlobals::mSunriseTime = 8; +const float WeatherGlobals::mSunsetTime = 18; +const float WeatherGlobals::mSunriseDuration = 2; +const float WeatherGlobals::mSunsetDuration = 2; +const float WeatherGlobals::mWeatherUpdateTime = 20.f; +const float WeatherGlobals::mThunderFrequency = .4; +const float WeatherGlobals::mThunderThreshold = 0.6; +const float WeatherGlobals::mThunderSoundDelay = 0.25; WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7a719252b..9353f7cd1 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -95,18 +95,18 @@ namespace MWWorld Script Color=255,20,20 */ - static const float mSunriseTime = 8; - static const float mSunsetTime = 18; - static const float mSunriseDuration = 2; - static const float mSunsetDuration = 2; + static const float mSunriseTime; + static const float mSunsetTime; + static const float mSunriseDuration; + static const float mSunsetDuration; - static const float mWeatherUpdateTime = 20.f; + static const float mWeatherUpdateTime; // morrowind sets these per-weather, but since they are only used by 'thunderstorm' // weather setting anyway, we can just as well set them globally - static const float mThunderFrequency = .4; - static const float mThunderThreshold = 0.6; - static const float mThunderSoundDelay = 0.25; + static const float mThunderFrequency; + static const float mThunderThreshold; + static const float mThunderSoundDelay; static const std::string mThunderSoundID0; static const std::string mThunderSoundID1; static const std::string mThunderSoundID2; From 2b3e75718c1bbe8f4408dfa85fb9c07faac15eac Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Mon, 19 Mar 2012 20:03:48 -0400 Subject: [PATCH 002/185] Updating everything --- apps/openmw/mwworld/physicssystem.cpp | 56 ++++++++++++++++++++++----- apps/openmw/mwworld/physicssystem.hpp | 2 + libs/openengine/bullet/trace.cpp | 4 +- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index bb2f9f8a9..11a43c7d3 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -13,6 +13,7 @@ #include "OgreTextureManager.h" + using namespace Ogre; namespace MWWorld { @@ -20,9 +21,11 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { + playerphysics = new playerMove; // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + playerphysics->mEngine = mEngine; } PhysicsSystem::~PhysicsSystem() @@ -68,55 +71,90 @@ namespace MWWorld { //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - + + //set the walkdirection to 0 (no movement) for every actor) for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { OEngine::Physic::PhysicActor* act = it->second; act->setWalkDirection(btVector3(0,0,0)); } - + playerMove::playercmd& pm_ref = playerphysics->cmd; + + pm_ref.rightmove = 0; + pm_ref.forwardmove = 0; + pm_ref.upmove = 0; + //playerphysics->ps.move_type = PM_NOCLIP; for (std::vector >::const_iterator iter (actors.begin()); iter!=actors.end(); ++iter) { OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first); - + //if(iter->first == "player") + // std::cout << "This is player\n"; //dirty stuff to get the camera orientation. Must be changed! Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first); Ogre::Vector3 dir; Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); + Ogre::Quaternion yawQuat = yawNode->getOrientation(); + Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); + Ogre::Quaternion both = yawQuat * pitchQuat; + + playerphysics->ps.viewangles.x = 0; + playerphysics->ps.viewangles.z = 0; + playerphysics->ps.viewangles.y = both.getYaw().valueDegrees() *-1 + 90; + //playerphysics->ps.viewangles.z = both.getPitch().valueDegrees(); + + if(mFreeFly) { - Ogre::Quaternion yawQuat = yawNode->getOrientation(); - Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); + Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); + pm_ref.rightmove = -dir1.x; + pm_ref.forwardmove = dir1.z; + + + + //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; + //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); + //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; dir = 0.07*(yawQuat*pitchQuat*dir1); } else { Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); + pm_ref.rightmove = -dir1.x; + pm_ref.forwardmove = dir1.z; + dir = 0.025*(quat*dir1); } + Pmove(playerphysics); //set the walk direction act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); } - mEngine->stepSimulation(duration); - + //mEngine->stepSimulation(duration); + Pmove(playerphysics); std::vector< std::pair > response; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { btVector3 newPos = it->second->getPosition(); + Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); - + if(it->first == "player"){ + + coord = playerphysics->ps.origin; + //std::cout << "Coord" << coord << "\n"; + coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y + + } response.push_back(std::pair(it->first, coord)); } + return response; } - void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) { diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 78cbde083..4fc8bee36 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -5,6 +5,7 @@ #include #include #include "ptr.hpp" +#include namespace MWWorld { @@ -49,6 +50,7 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; + playerMove* playerphysics; PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 6baec8c83..49e12064e 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -32,7 +32,7 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr Ogre::Vector3 endReplace = startReplace; endReplace.y -= .25; - const bool hasHit = NewPhysicsTrace(&out, startReplace, endReplace, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); if(hasHit) std::cout << "Has hit\n"; if (out.fraction < 0.001f) @@ -102,7 +102,7 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const btVector3 btend(end.x, end.y, end.z); const btQuaternion btrot(rotation.y, rotation.x, rotation.z); - const btBoxShape newshape(btVector3(1000, 1000, 1000) ); + const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); const btTransform from(btrot, btstart); const btTransform to(btrot, btend); float x = from.getOrigin().getX(); From f9bb19fcdc8111ab405cbc8673dbf9c5800b1986 Mon Sep 17 00:00:00 2001 From: gugus Date: Fri, 23 Mar 2012 15:18:09 +0100 Subject: [PATCH 003/185] begining factions --- apps/openmw/mwworld/player.cpp | 53 ++++++++++++++++++++++++++++++++++ apps/openmw/mwworld/player.hpp | 21 ++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5bfb82138..270ffa55c 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -89,4 +89,57 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } + + Player::Faction Player::getFaction(std::string faction) + { + for(std::list::iterator it = mFactions.begin(); it != mFactions.end();it++) + { + if(it->name == faction) return *it; + } + //faction was not found->dummy faction + Player::Faction fact; + fact.id = "not found"; + fact.name = "not found"; + fact.rank = -10; + fact.expelled = false; + return fact; + } + + void Player::addFaction(std::string faction) + { + if(getFaction(faction).name == "not found") + { + Player::Faction fact; + const ESM::Faction* eFact = mWorld.getStore().factions.find(faction); + fact.expelled = false; + fact.rank = 0; + fact.name = faction; + fact.id = eFact->id; + mFactions.push_back(fact); + } + } + + int Player::getRank(std::string faction) + { + Player::Faction fact = getFaction(faction); + return fact.rank; + } + + void Player::setRank(std::string faction,int rank) + { + Player::Faction fact = getFaction(faction); + fact.rank = rank; + } + + bool Player::isExpelled(std::string faction) + { + Player::Faction fact = getFaction(faction); + return fact.expelled; + } + + void Player::setExpelled(std::string faction,bool expelled) + { + Player::Faction fact = getFaction(faction); + fact.expelled = expelled; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 01c71da43..8129c4d8e 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -4,6 +4,7 @@ #include "OgreCamera.h" #include +#include #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" @@ -20,6 +21,13 @@ namespace MWWorld /// \brief NPC object representing the player and additional player data class Player { + struct Faction + { + std::string id,name; + int rank; + bool expelled; + }; + ESMS::LiveCellRef mPlayer; MWWorld::Ptr::CellStore *mCellStore; MWRender::Player *mRenderer; @@ -29,9 +37,12 @@ namespace MWWorld std::string mRace; std::string mBirthsign; ESM::Class *mClass; + std::list mFactions; bool mAutoMove; int mForwardBackward; + Faction getFaction(std::string faction); + public: Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); @@ -108,6 +119,16 @@ namespace MWWorld void setAutoMove (bool enable); + void addFaction(std::string faction); + + int getRank(std::string faction); + + void setRank(std::string faction,int rank); + + bool isExpelled(std::string faction); + + void setExpelled(std::string faction,bool expelled); + void setLeftRight (int value); void setForwardBackward (int value); From 0c61f0d2942036d52a5703f9c17c968484d08dca Mon Sep 17 00:00:00 2001 From: gugus Date: Wed, 28 Mar 2012 11:45:46 +0200 Subject: [PATCH 004/185] test stuff --- apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/statsextensions.cpp | 39 +++++++++++++++++ apps/openmw/mwworld/player.cpp | 53 +++++++++++++++++------- apps/openmw/mwworld/player.hpp | 14 ++++--- 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index eab5bf846..713ac43b0 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -123,4 +123,5 @@ op 0x200013d: FadeOut op 0x200013e: FadeTo op 0x200013f: GetCurrentWeather op 0x2000140: ChangeWeather -opcodes 0x2000141-0x3ffffff unused +op 0x2000141: OpPCJoinFaction +opcodes 0x2000142-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 0e97a39cf..85ac54348 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -8,6 +8,8 @@ #include #include "../mwworld/class.hpp" +#include "../mwworld/environment.hpp" +#include "../mwworld/player.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" @@ -280,6 +282,36 @@ namespace MWScript } }; + class OpPCJoinFaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + context.getEnvironment().mWorld->getPlayer().addFaction(factionID); + } + }; + + class OpPCRaiseRank : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + context.getEnvironment().mWorld->getPlayer().raiseRank(factionID); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -310,6 +342,8 @@ namespace MWScript const int opcodeSetSkillExplicit = 0x20000df; const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; + const int opcodePCJoinFaction = 0x2000141; + const int opcodePCRaiseRank = 0x2000142; void registerExtensions (Compiler::Extensions& extensions) { @@ -381,6 +415,8 @@ namespace MWScript extensions.registerInstruction (mod + skills[i], "l", opcodeModSkill+i, opcodeModSkillExplicit+i); } + extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); + extensions.registerInstruction("PCRaiseRank","S",opcodePCRaiseRank); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -436,6 +472,9 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill (i)); interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } + + interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); + interpreter.installSegment5(opcodePCRaiseRank,new OpPCRaiseRank); } } } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 270ffa55c..518b1d519 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -90,11 +90,11 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } - Player::Faction Player::getFaction(std::string faction) + Player::Faction Player::getFaction(std::string factionID) { for(std::list::iterator it = mFactions.begin(); it != mFactions.end();it++) { - if(it->name == faction) return *it; + if(it->name == factionID) return *it; } //faction was not found->dummy faction Player::Faction fact; @@ -105,41 +105,66 @@ namespace MWWorld return fact; } - void Player::addFaction(std::string faction) + void Player::addFaction(std::string factionID) { - if(getFaction(faction).name == "not found") + if(getFaction(factionID).name == "not found") { Player::Faction fact; - const ESM::Faction* eFact = mWorld.getStore().factions.find(faction); + const ESM::Faction* eFact = mWorld.getStore().factions.find(factionID); fact.expelled = false; fact.rank = 0; - fact.name = faction; + fact.name = eFact->name; fact.id = eFact->id; mFactions.push_back(fact); } } - int Player::getRank(std::string faction) + int Player::getRank(std::string factionID) { - Player::Faction fact = getFaction(faction); + Player::Faction fact = getFaction(factionID); return fact.rank; } - void Player::setRank(std::string faction,int rank) + void Player::setRank(std::string factionID,int rank) { - Player::Faction fact = getFaction(faction); + Player::Faction fact = getFaction(factionID); fact.rank = rank; } - bool Player::isExpelled(std::string faction) + void Player::raiseRank(std::string factionID) { - Player::Faction fact = getFaction(faction); + if(getFaction(factionID).name == "not found") + { + addFaction(factionID); + setRank(factionID,1); + } + else + { + setRank(factionID,getRank(factionID) + 1); + } + } + + void Player::lowerRank(std::string factionID) + { + if(getFaction(factionID).name == "not found") + { + std::cout << "cannot lower the rank of the player: faction no found. Faction: "<< factionID << std::endl; + } + else + { + setRank(factionID,getRank(factionID) - 1); + } + } + + bool Player::isExpelled(std::string factionID) + { + Player::Faction fact = getFaction(factionID); return fact.expelled; } - void Player::setExpelled(std::string faction,bool expelled) + void Player::setExpelled(std::string factionID,bool expelled) { - Player::Faction fact = getFaction(faction); + Player::Faction fact = getFaction(factionID); fact.expelled = expelled; } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 8129c4d8e..628a23826 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -119,15 +119,19 @@ namespace MWWorld void setAutoMove (bool enable); - void addFaction(std::string faction); + void addFaction(std::string factionID); - int getRank(std::string faction); + int getRank(std::string factionID); - void setRank(std::string faction,int rank); + void setRank(std::string factionID,int rank); - bool isExpelled(std::string faction); + void raiseRank(std::string factionID); - void setExpelled(std::string faction,bool expelled); + void lowerRank(std::string factionID); + + bool isExpelled(std::string factionID); + + void setExpelled(std::string factionID,bool expelled); void setLeftRight (int value); From d717b7b9dd3a73631a811bd243983bbd63860f7b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 30 Mar 2012 16:18:58 +0200 Subject: [PATCH 005/185] factored out actor related game mechanics code into a separate class --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 44 +++++++++++++++++++ apps/openmw/mwmechanics/actors.hpp | 45 ++++++++++++++++++++ apps/openmw/mwmechanics/mechanicsmanager.cpp | 26 +++-------- apps/openmw/mwmechanics/mechanicsmanager.hpp | 4 +- 5 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 apps/openmw/mwmechanics/actors.cpp create mode 100644 apps/openmw/mwmechanics/actors.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2d49a414c..e16bd181d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanager stat creaturestats magiceffects movement + mechanicsmanager stat creaturestats magiceffects movement actors ) # Main executable diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp new file mode 100644 index 000000000..e4fba8a9c --- /dev/null +++ b/apps/openmw/mwmechanics/actors.cpp @@ -0,0 +1,44 @@ + +#include "actors.hpp" + +#include "../mwworld/class.hpp" + +namespace MWMechanics +{ + Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment) {} + + void Actors::addActor (const MWWorld::Ptr& ptr) + { + mActors.insert (ptr); + } + + void Actors::removeActor (const MWWorld::Ptr& ptr) + { + mActors.erase (ptr); + } + + void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) + { + std::set::iterator iter = mActors.begin(); + + while (iter!=mActors.end()) + if (iter->getCell()==cellStore) + { + mActors.erase (iter++); + } + else + ++iter; + } + + void Actors::update (std::vector >& movement) + { + for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); + ++iter) + { + Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); + + if (vector!=Ogre::Vector3::ZERO) + movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); + } + } +} diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp new file mode 100644 index 000000000..d3a372472 --- /dev/null +++ b/apps/openmw/mwmechanics/actors.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWMECHANICS_ACTORS_H +#define GAME_MWMECHANICS_ACTORS_H + +#include +#include +#include + +#include "../mwworld/ptr.hpp" + +namespace Ogre +{ + class Vector3; +} + +namespace MWWorld +{ + class Environment; +} + +namespace MWMechanics +{ + class Actors + { + MWWorld::Environment& mEnvironment; + std::set mActors; + + public: + + Actors (MWWorld::Environment& environment); + + void addActor (const MWWorld::Ptr& ptr); + ///< Register an actor for stats management + + void removeActor (const MWWorld::Ptr& ptr); + ///< Deregister an actor for stats management + + void dropActors (const MWWorld::Ptr::CellStore *cellStore); + ///< Deregister all actors in the given cell. + + void update (std::vector >& movement); + ///< Update actor stats and store desired velocity vectors in \a movement + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 7ed81f785..f669ea65c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -222,14 +222,14 @@ namespace MWMechanics MechanicsManager::MechanicsManager (MWWorld::Environment& environment) : mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false), - mRaceSelected (false) + mRaceSelected (false), mActors (environment) { buildPlayer(); } void MechanicsManager::addActor (const MWWorld::Ptr& ptr) { - mActors.insert (ptr); + mActors.addActor (ptr); } void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) @@ -237,7 +237,7 @@ namespace MWMechanics if (ptr==mWatched) mWatched = MWWorld::Ptr(); - mActors.erase (ptr); + mActors.removeActor (ptr); } void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore) @@ -245,16 +245,7 @@ namespace MWMechanics if (!mWatched.isEmpty() && mWatched.getCell()==cellStore) mWatched = MWWorld::Ptr(); - std::set::iterator iter = mActors.begin(); - - while (iter!=mActors.end()) - if (iter->getCell()==cellStore) - { - //std::cout << "Erasing an actor"; - mActors.erase (iter++); - } - else - ++iter; + mActors.dropActors (cellStore); } void MechanicsManager::watchActor (const MWWorld::Ptr& ptr) @@ -345,14 +336,7 @@ namespace MWMechanics mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills); } - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); - ++iter) - { - Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); - - if (vector!=Ogre::Vector3::ZERO) - movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); - } + mActors.update (movement); } void MechanicsManager::setPlayerName (const std::string& name) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index 2e2192638..bf0a6215a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -1,7 +1,6 @@ #ifndef GAME_MWMECHANICS_MECHANICSMANAGER_H #define GAME_MWMECHANICS_MECHANICSMANAGER_H -#include #include #include @@ -9,6 +8,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "actors.hpp" namespace Ogre { @@ -25,13 +25,13 @@ namespace MWMechanics class MechanicsManager { MWWorld::Environment& mEnvironment; - std::set mActors; MWWorld::Ptr mWatched; CreatureStats mWatchedCreature; NpcStats mWatchedNpc; bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; + Actors mActors; void buildPlayer(); ///< build player according to stored class/race/birthsign information. Will From a1d3516e0a23c049eca4e787d8dc5e06193f1af9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 30 Mar 2012 17:01:23 +0200 Subject: [PATCH 006/185] constness fix --- apps/openmw/mwworld/ptr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index c31c53122..d6e485f41 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -39,7 +39,7 @@ namespace MWWorld return mPtr.empty(); } - const std::type_info& getType() + const std::type_info& getType() const { assert (!mPtr.empty()); return mPtr.type(); From 0892df0ad38ca0eddf0da8b0c46ba7676f4dc0a1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 30 Mar 2012 17:01:55 +0200 Subject: [PATCH 007/185] framework for gamemechanics-realted actor updated --- apps/openmw/engine.cpp | 5 +-- apps/openmw/mwmechanics/actors.cpp | 34 ++++++++++++++++++-- apps/openmw/mwmechanics/actors.hpp | 12 +++++-- apps/openmw/mwmechanics/mechanicsmanager.cpp | 5 +-- apps/openmw/mwmechanics/mechanicsmanager.hpp | 6 +++- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 441c22769..45ed0abd4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -148,7 +148,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update actors std::vector > movement; - mEnvironment.mMechanicsManager->update (movement); + mEnvironment.mMechanicsManager->update (movement, mEnvironment.mFrameDuration, + mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game); if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game) mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration); @@ -317,7 +318,7 @@ void OMW::Engine::go() // to find core.xml here. //addResourcesDirectory(mResDir); - + addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e4fba8a9c..d532c6f09 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,11 +1,25 @@ #include "actors.hpp" +#include + +#include + #include "../mwworld/class.hpp" namespace MWMechanics { - Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment) {} + void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) + { + + } + + void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) + { + + } + + Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment), mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) { @@ -30,8 +44,24 @@ namespace MWMechanics ++iter; } - void Actors::update (std::vector >& movement) + void Actors::update (std::vector >& movement, float duration, + bool paused) { + mDuration += duration; + + if (mDuration>=0.25) + { + for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) + { + updateActor (*iter, mDuration); + + if (iter->getTypeName()==typeid (ESM::NPC).name()) + updateNpc (*iter, mDuration, paused); + } + + mDuration = 0; + } + for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index d3a372472..7ff33b63b 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -21,8 +21,13 @@ namespace MWMechanics { class Actors { - MWWorld::Environment& mEnvironment; - std::set mActors; + MWWorld::Environment& mEnvironment; + std::set mActors; + float mDuration; + + void updateActor (const MWWorld::Ptr& ptr, float duration); + + void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); public: @@ -37,7 +42,8 @@ namespace MWMechanics void dropActors (const MWWorld::Ptr::CellStore *cellStore); ///< Deregister all actors in the given cell. - void update (std::vector >& movement); + void update (std::vector >& movement, + float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index f669ea65c..3c93857ef 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -253,7 +253,8 @@ namespace MWMechanics mWatched = ptr; } - void MechanicsManager::update (std::vector >& movement) + void MechanicsManager::update (std::vector >& movement, + float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -336,7 +337,7 @@ namespace MWMechanics mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills); } - mActors.update (movement); + mActors.update (movement, duration, paused); } void MechanicsManager::setPlayerName (const std::string& name) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index bf0a6215a..a7defe178 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -60,8 +60,12 @@ namespace MWMechanics ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - void update (std::vector >& movement); + void update (std::vector >& movement, float duration, + bool paused); ///< Update actor stats and store desired velocity vectors in \a movement + /// + /// \param paused In game type does not currently advance (this usually means some GUI + /// component is up). void setPlayerName (const std::string& name); ///< Set player name. From 751e7d2199d595b2024d8172aef1e03670d0eaa9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 31 Mar 2012 17:26:15 +0200 Subject: [PATCH 008/185] basic auto-equipping (picks the first matching item --- apps/openmw/mwmechanics/actors.cpp | 5 ++- apps/openmw/mwworld/inventorystore.cpp | 58 +++++++++++++++++++++++++- apps/openmw/mwworld/inventorystore.hpp | 14 ++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d532c6f09..e68b99597 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -6,6 +6,7 @@ #include #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" namespace MWMechanics { @@ -16,7 +17,9 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { - + if (!paused) + MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( + MWWorld::Class::get (ptr).getNpcStats (ptr)); } Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment), mDuration (0) {} diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index e64c9785f..aedd119c8 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,8 @@ #include "class.hpp" +#include /// \todo remove after rendering is implemented + void MWWorld::InventoryStore::copySlots (const InventoryStore& store) { // some const-trickery, required because of a flaw in the handling of MW-references and the @@ -24,10 +26,15 @@ void MWWorld::InventoryStore::copySlots (const InventoryStore& store) } } -MWWorld::InventoryStore::InventoryStore() +void MWWorld::InventoryStore::initSlots (TSlots& slots) { for (int i=0; i, bool> itemsSlots = + MWWorld::Class::get (*iter).getEquipmentSlots (*iter); + + for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); + iter2!=itemsSlots.first.end(); ++iter2) + { + /// \todo comapre item with item in slot + if (slots.at (*iter2)==end()) + { + /// \todo unstack, if reqquired (itemsSlots.second) + + slots[*iter2] = iter; + break; + } + } + } + + bool changed = false; + + for (std::size_t i=0; i mSlots; + typedef std::vector TSlots; + + mutable TSlots mSlots; void copySlots (const InventoryStore& store); + void initSlots (TSlots& slots); + public: InventoryStore(); @@ -52,6 +61,9 @@ namespace MWWorld ///< \note \a iteartor can be an end-iterator ContainerStoreIterator getSlot (int slot); + + void autoEquip (const MWMechanics::NpcStats& stats); + ///< Auto equip items according to stats and item value. }; } From d09f0610eaaf5128b9d849e3bc99868fcf17f43e Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Sun, 1 Apr 2012 20:36:57 +0300 Subject: [PATCH 009/185] Add basic windows pinning Create WindowPinnableBase class for windows which should be allowed to be pinned. Add skin for pinnable windows - currently just a copy of normal window with 1 extra button (hopefully this can be improved later). Handle clicking on PinToggle button (pinning/unpinning a window). --- apps/openmw/mwgui/stats_window.cpp | 2 +- apps/openmw/mwgui/stats_window.hpp | 4 +- apps/openmw/mwgui/window_pinnable_base.cpp | 31 +++++++++ apps/openmw/mwgui/window_pinnable_base.hpp | 24 +++++++ files/mygui/openmw_stats_window_layout.xml | 2 +- files/mygui/openmw_windows.skin.xml | 81 ++++++++++++++++++++++ libs/openengine/gui/layout.hpp | 2 +- 7 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 apps/openmw/mwgui/window_pinnable_base.cpp create mode 100644 apps/openmw/mwgui/window_pinnable_base.hpp diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 12b0dcc79..3ded9713a 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -12,7 +12,7 @@ using namespace MWGui; const int StatsWindow::lineHeight = 18; StatsWindow::StatsWindow (WindowManager& parWindowManager) - : WindowBase("openmw_stats_window_layout.xml", parWindowManager) + : WindowPinnableBase("openmw_stats_window_layout.xml", parWindowManager) , skillAreaWidget(NULL) , skillClientWidget(NULL) , skillScrollerWidget(NULL) diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 2ff170f57..081a75d56 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -9,13 +9,13 @@ #include #include "../mwmechanics/stat.hpp" -#include "window_base.hpp" +#include "window_pinnable_base.hpp" namespace MWGui { class WindowManager; - class StatsWindow : public WindowBase + class StatsWindow : public WindowPinnableBase { public: typedef std::pair Faction; diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp new file mode 100644 index 000000000..cca593c9c --- /dev/null +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -0,0 +1,31 @@ +#include "window_pinnable_base.hpp" +#include "window_manager.hpp" + +using namespace MWGui; + +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager), mIsPinned(false) +{ + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); +} + +void WindowPinnableBase::setVisible(bool b) +{ + // Pinned windows can not be hidden + if (mIsPinned && !b) + return; + + WindowBase::setVisible(b); +} + +void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) +{ + if ("PinToggle" == eventName) + { + mIsPinned = !mIsPinned; + } + + eventDone(this); +} + diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp new file mode 100644 index 000000000..0e3c27c86 --- /dev/null +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -0,0 +1,24 @@ +#ifndef MWGUI_WINDOW_PINNABLE_BASE_H +#define MWGUI_WINDOW_PINNABLE_BASE_H + +#include "window_base.hpp" + +namespace MWGui +{ + class WindowManager; + + class WindowPinnableBase: public WindowBase + { + public: + WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager); + void setVisible(bool b); + + private: + void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); + + bool mIsPinned; + }; +} + +#endif + diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 1380d474c..fd99f863e 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 3ee33124c..7c194ea5d 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -289,6 +289,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index e73b2d1ce..05a23e8ae 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -103,7 +103,7 @@ namespace GUI )); } - void setVisible(bool b) + virtual void setVisible(bool b) { mMainWidget->setVisible(b); } From 911ca4be8950b6b590104cb85a35f86e5edc0d5d Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Sun, 1 Apr 2012 20:39:53 +0300 Subject: [PATCH 010/185] Move MapWindow to separate files Separate MapWindow from bunch of classes in layouts.cpp/hpp Inherit it from WindowPinnableBase. TODO: map arrow (player position) updates orientation only when you open the inventory. When the map window is pinned, the arrow direction is not updated. --- apps/openmw/mwgui/layouts.cpp | 93 ------------------------ apps/openmw/mwgui/layouts.hpp | 24 ------- apps/openmw/mwgui/map_window.cpp | 104 +++++++++++++++++++++++++++ apps/openmw/mwgui/map_window.hpp | 33 +++++++++ apps/openmw/mwgui/window_manager.cpp | 3 +- 5 files changed, 139 insertions(+), 118 deletions(-) create mode 100644 apps/openmw/mwgui/map_window.cpp create mode 100644 apps/openmw/mwgui/map_window.hpp diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/layouts.cpp index de74214ee..af068ffae 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/layouts.cpp @@ -181,99 +181,6 @@ void HUD::setPlayerPos(const float x, const float y) compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); } -MapWindow::MapWindow() - : Layout("openmw_map_window_layout.xml") - , mGlobal(false) - , mVisible(false) -{ - setCoord(500,0,320,300); - setText("WorldButton", "World"); - setImage("Compass", "textures\\compass.dds"); - - // Obviously you should override this later on - setCellName("No Cell Loaded"); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mPlayerArrow, "Compass"); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - - MyGUI::Button* eventbox; - getWidget(eventbox, "EventBox"); - eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, this); -} - -void MapWindow::setVisible(bool b) -{ - mMainWidget->setVisible(b); - if (b) - mVisible = true; - else - mVisible = false; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - static_cast(mMainWidget)->setCaption(cellName); - adjustWindowCaption(); -} - -void MapWindow::setPlayerPos(const float x, const float y) -{ - if (mGlobal || mVisible) return; - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); -} - -void MapWindow::setPlayerDir(const float x, const float y) -{ - if (!mVisible) return; - MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - if (!mGlobal) - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - if (!mGlobal) - { - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - - mLastDragPos = MyGUI::IntPoint(_left, _top); - } -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaption( mGlobal ? "Local" : "World" ); -} - LocalMapBase::LocalMapBase() : mCurX(0) , mCurY(0) diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp index 614479ccc..30bea579c 100644 --- a/apps/openmw/mwgui/layouts.hpp +++ b/apps/openmw/mwgui/layouts.hpp @@ -82,30 +82,6 @@ namespace MWGui MyGUI::TextBox* batchcounter; }; - class MapWindow : public OEngine::GUI::Layout, public LocalMapBase - { - public: - MapWindow(); - virtual ~MapWindow(){} - - void setVisible(bool b); - void setPlayerPos(const float x, const float y); - void setPlayerDir(const float x, const float y); - void setCellName(const std::string& cellName); - - private: - void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onWorldButtonClicked(MyGUI::Widget* _sender); - - MyGUI::ScrollView* mGlobalMap; - MyGUI::ImageBox* mPlayerArrow; - MyGUI::Button* mButton; - MyGUI::IntPoint mLastDragPos; - bool mVisible; - bool mGlobal; - }; - class MainMenu : public OEngine::GUI::Layout { public: diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp new file mode 100644 index 000000000..631f61c9d --- /dev/null +++ b/apps/openmw/mwgui/map_window.cpp @@ -0,0 +1,104 @@ +#include "map_window.hpp" +/* +#include "../mwmechanics/mechanicsmanager.hpp" +#include "window_manager.hpp" + +#include +#include +#include + +#undef min +#undef max +*/ +using namespace MWGui; + +MapWindow::MapWindow(WindowManager& parWindowManager) : + MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), + mGlobal(false), + mVisible(false) +{ + setCoord(500,0,320,300); + setText("WorldButton", "World"); + setImage("Compass", "textures\\compass.dds"); + + // Obviously you should override this later on + setCellName("No Cell Loaded"); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mPlayerArrow, "Compass"); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + + MyGUI::Button* eventbox; + getWidget(eventbox, "EventBox"); + eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, this); +} + +void MapWindow::setVisible(bool b) +{ + WindowPinnableBase::setVisible(b); + mVisible = b; +} + +void MapWindow::setCellName(const std::string& cellName) +{ + static_cast(mMainWidget)->setCaption(cellName); + adjustWindowCaption(); +} + +void MapWindow::setPlayerPos(const float x, const float y) +{ + if (mGlobal || mVisible) return; + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); +} + +void MapWindow::setPlayerDir(const float x, const float y) +{ + if (!mVisible) return; + MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(x,y); + rotatingSubskin->setAngle(angle); +} + +void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + if (!mGlobal) + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + + if (!mGlobal) + { + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + + mLastDragPos = MyGUI::IntPoint(_left, _top); + } +} + +void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) +{ + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaption( mGlobal ? "Local" : "World" ); +} + diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp new file mode 100644 index 000000000..2fdc0d91a --- /dev/null +++ b/apps/openmw/mwgui/map_window.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_MAPWINDOW_H +#define MWGUI_MAPWINDOW_H + +#include "layouts.hpp" +#include "window_pinnable_base.hpp" + +namespace MWGui +{ + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase + { + public: + MapWindow(WindowManager& parWindowManager); + virtual ~MapWindow(){} + + void setVisible(bool b); + void setPlayerPos(const float x, const float y); + void setPlayerDir(const float x, const float y); + void setCellName(const std::string& cellName); + + private: + void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onWorldButtonClicked(MyGUI::Widget* _sender); + + MyGUI::ScrollView* mGlobalMap; + MyGUI::ImageBox* mPlayerArrow; + MyGUI::Button* mButton; + MyGUI::IntPoint mLastDragPos; + bool mVisible; + bool mGlobal; + }; +} +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 49b6e644d..4d7b9f901 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -4,6 +4,7 @@ #include "review.hpp" #include "dialogue.hpp" #include "dialogue_history.hpp" +#include "map_window.hpp" #include "stats_window.hpp" #include "messagebox.hpp" @@ -71,7 +72,7 @@ WindowManager::WindowManager(MWWorld::Environment& environment, hud = new HUD(w,h, showFPSLevel); menu = new MainMenu(w,h); - map = new MapWindow(); + map = new MapWindow(*this); stats = new StatsWindow(*this); console = new Console(w,h, environment, extensions); mJournal = new JournalWindow(*this); From 91a377df86021d99e7c45c9ae16dc68d7e45a8ab Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Sun, 1 Apr 2012 23:51:49 +0300 Subject: [PATCH 011/185] Fix behaviour of the MapWindow The map now will track player's position/rotation when pinned, and will not update if position/rotation didn't change since last frame. --- apps/openmw/mwgui/map_window.cpp | 22 ++++++++++++---------- apps/openmw/mwgui/map_window.hpp | 6 ++++-- apps/openmw/mwgui/window_pinnable_base.cpp | 7 ++++--- apps/openmw/mwgui/window_pinnable_base.hpp | 4 +++- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 631f61c9d..b4e8aa4d6 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -14,8 +14,11 @@ using namespace MWGui; MapWindow::MapWindow(WindowManager& parWindowManager) : MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), - mGlobal(false), - mVisible(false) + mGlobal(false), + mLastPositionX(0.0f), + mLastPositionY(0.0f), + mLastDirectionX(0.0f), + mLastDirectionY(0.0f) { setCoord(500,0,320,300); setText("WorldButton", "World"); @@ -39,12 +42,6 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : LocalMapBase::init(mLocalMap, this); } -void MapWindow::setVisible(bool b) -{ - WindowPinnableBase::setVisible(b); - mVisible = b; -} - void MapWindow::setCellName(const std::string& cellName) { static_cast(mMainWidget)->setCaption(cellName); @@ -53,7 +50,7 @@ void MapWindow::setCellName(const std::string& cellName) void MapWindow::setPlayerPos(const float x, const float y) { - if (mGlobal || mVisible) return; + if (mGlobal || !mVisible || (x == mLastPositionX && y == mLastPositionY)) return; MyGUI::IntSize size = mLocalMap->getCanvasSize(); MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); MyGUI::IntCoord viewsize = mLocalMap->getCoord(); @@ -61,16 +58,21 @@ void MapWindow::setPlayerPos(const float x, const float y) mLocalMap->setViewOffset(pos); mPlayerArrow->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); + mLastPositionX = x; + mLastPositionY = y; } void MapWindow::setPlayerDir(const float x, const float y) { - if (!mVisible) return; + if (!mVisible || (x == mLastDirectionX && y == mLastDirectionY)) return; MyGUI::ISubWidget* main = mPlayerArrow->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); + + mLastDirectionX = x; + mLastDirectionY = y; } void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 2fdc0d91a..cad652bff 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -12,7 +12,6 @@ namespace MWGui MapWindow(WindowManager& parWindowManager); virtual ~MapWindow(){} - void setVisible(bool b); void setPlayerPos(const float x, const float y); void setPlayerDir(const float x, const float y); void setCellName(const std::string& cellName); @@ -26,8 +25,11 @@ namespace MWGui MyGUI::ImageBox* mPlayerArrow; MyGUI::Button* mButton; MyGUI::IntPoint mLastDragPos; - bool mVisible; bool mGlobal; + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; }; } #endif diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index cca593c9c..07f0ea278 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -4,7 +4,7 @@ using namespace MWGui; WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mIsPinned(false) + : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) { MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); @@ -13,17 +13,18 @@ WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, WindowManag void WindowPinnableBase::setVisible(bool b) { // Pinned windows can not be hidden - if (mIsPinned && !b) + if (mPinned && !b) return; WindowBase::setVisible(b); + mVisible = b; } void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) { if ("PinToggle" == eventName) { - mIsPinned = !mIsPinned; + mPinned = !mPinned; } eventDone(this); diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 0e3c27c86..f3cec847f 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -16,7 +16,9 @@ namespace MWGui private: void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); - bool mIsPinned; + protected: + bool mPinned; + bool mVisible; }; } From b380e71832d5bc35aded3deee5e1752d23e3d79f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Apr 2012 14:32:21 +0200 Subject: [PATCH 012/185] fixed underwater wireframe mode --- apps/openmw/mwrender/renderingmanager.hpp | 3 --- apps/openmw/mwrender/water.cpp | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 81907a938..fc32b4dd2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -31,11 +31,8 @@ namespace Ogre { - class Camera; - class Viewport; class SceneManager; class SceneNode; - class RaySceneQuery; class Quaternion; class Vector3; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9de55e3a5..cbf9c5b29 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -70,7 +70,7 @@ void Water::toggle() void Water::checkUnderwater(float y) { - if ((mIsUnderwater && y > mTop) || !mWater->isVisible()) + if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { try { Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); @@ -78,7 +78,7 @@ void Water::checkUnderwater(float y) mIsUnderwater = false; } - if (!mIsUnderwater && y < mTop && mWater->isVisible()) + if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { try { Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); From 57299571d5a1d76ce8666e1d7df6f7721d0c0d15 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Mon, 2 Apr 2012 22:08:46 -0400 Subject: [PATCH 013/185] Preparing for clothes/armor --- apps/openmw/mwclass/npc.cpp | 2 + apps/openmw/mwrender/npcanimation.cpp | 19 +- apps/openmw/mwrender/occlusionquery.cpp | 46 +- apps/openmw/mwrender/occlusionquery.hpp | 8 + apps/openmw/mwworld/physicssystem.cpp | 34 +- apps/openmw/mwworld/physicssystem.hpp | 3 +- apps/openmw/mwworld/weather.cpp | 34 +- apps/openmw/mwworld/world.cpp | 60 +- apps/openmw/mwworld/world.hpp | 18 +- components/bsa/bsa_archive.cpp | 6 +- components/nifogre/ogre_nif_loader.cpp | 14 +- libs/openengine/bullet/pmove.cpp | 2042 ----------------------- libs/openengine/bullet/pmove.h | 197 --- libs/openengine/bullet/trace.cpp | 188 --- 14 files changed, 169 insertions(+), 2502 deletions(-) delete mode 100644 libs/openengine/bullet/pmove.cpp delete mode 100644 libs/openengine/bullet/pmove.h delete mode 100644 libs/openengine/bullet/trace.cpp diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a94d27d..94bcbb31f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -93,7 +93,9 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { + std::cout << "Inserting NPC\n"; renderingInterface.getActors().insertNPC(ptr); + } void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c6fe023d6..a4fd15b74 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -14,6 +14,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O ESMS::LiveCellRef *ref = ptr.get(); + //Part selection on last character of the file string // " Tri Chest // * Tri Tail @@ -65,6 +66,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O 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 @@ -82,6 +84,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O } textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel); insert->attachObject(base); + if(female) insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); @@ -124,6 +127,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg"); } + if(foot){ if(bodyRaceID.compare("b_n_khajiit_m_") == 0) { @@ -190,28 +194,29 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insertBoundedPart("meshes\\" + hair->model, "Head"); if (chest){ - insertFreePart("meshes\\" + chest->model, ">\"", insert); + insertFreePart("meshes\\" + chest->model, ":\"", insert); } if (handr){ - insertFreePart("meshes\\" + handr->model , ">?", insert); + insertFreePart("meshes\\" + handr->model , ":?", insert); } if (handl){ - insertFreePart("meshes\\" + handl->model, ">>", insert); + insertFreePart("meshes\\" + handl->model, ":>", insert); } if(tail){ - insertFreePart("meshes\\" + tail->model, ">*", insert); + insertFreePart("meshes\\" + tail->model, ":*", insert); } if(feet){ std::string num = getUniqueID(feet->model); - insertFreePart("meshes\\" + feet->model,"><", insert); - insertFreePart("meshes\\" + feet->model,">:", insert); + 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){ @@ -262,7 +267,7 @@ void NpcAnimation::runAnimation(float timepassed){ time = startTime + (time - stopTime); } - handleAnimationTransforms(); + handleAnimationTransforms(); std::vector*>::iterator shapepartsiter = shapeparts.begin(); std::vector::iterator entitypartsiter = entityparts.begin(); diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 29cfe33fe..781b522b6 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -5,13 +5,14 @@ #include #include #include +#include using namespace MWRender; using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), - mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), + mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), mBBNode(0) { @@ -84,7 +85,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderQueueListener(this); mDoQuery = true; - mDoQuery2 = true; } OcclusionQuery::~OcclusionQuery() @@ -100,7 +100,7 @@ bool OcclusionQuery::supported() return mSupported; } -void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, +void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, const LightList* pLightList, bool suppressRenderStateChanges) { // The following code activates and deactivates the occlusion queries @@ -134,7 +134,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass mActiveQuery = mSingleObjectQuery; mObjectWasVisible = true; } - + if (mActiveQuery != NULL) mActiveQuery->beginOcclusionQuery(); } @@ -195,7 +195,6 @@ void OcclusionQuery::update(float duration) // Stop occlusion queries until we get their information // (may not happen on the same frame they are requested in) mDoQuery = false; - mDoQuery2 = false; if (!mSunTotalAreaQuery->isStillOutstanding() && !mSunVisibleAreaQuery->isStillOutstanding() @@ -264,3 +263,40 @@ bool OcclusionQuery::getTestResult() return mTestResult; } + +bool OcclusionQuery::isPotentialOccluder(Ogre::SceneNode* node) +{ + bool result = false; + for (unsigned int i=0; i < node->numAttachedObjects(); ++i) + { + MovableObject* ob = node->getAttachedObject(i); + std::string type = ob->getMovableType(); + if (type == "Entity") + { + Entity* ent = static_cast(ob); + for (unsigned int j=0; j < ent->getNumSubEntities(); ++j) + { + // if any sub entity has a material with depth write off, + // consider the object as not an occluder + MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); + + Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) + { + Technique* tech = techIt.getNext(); + Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + return false; + else + result = true; + } + } + } + } + } + return result; +} diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index b655c8e46..c76fcccd0 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -46,6 +46,14 @@ namespace MWRender */ bool occlusionTestPending(); + /** + * Checks if the objects held by this scenenode + * can be considered as potential occluders + * (which might not be the case when transparency is involved) + * @param Scene node + */ + bool isPotentialOccluder(Ogre::SceneNode* node); + /** * @return true if the object tested in the last request was occluded */ diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 71e12e369..ed96f47d6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,11 +21,11 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { - playerphysics = new playerMove; + // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - playerphysics->mEngine = mEngine; + } PhysicsSystem::~PhysicsSystem() @@ -101,11 +101,9 @@ namespace MWWorld OEngine::Physic::PhysicActor* act = it->second; act->setWalkDirection(btVector3(0,0,0)); } - playerMove::playercmd& pm_ref = playerphysics->cmd; - pm_ref.rightmove = 0; - pm_ref.forwardmove = 0; - pm_ref.upmove = 0; + + //playerphysics->ps.move_type = PM_NOCLIP; for (std::vector >::const_iterator iter (actors.begin()); iter!=actors.end(); ++iter) @@ -123,9 +121,7 @@ namespace MWWorld Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); Ogre::Quaternion both = yawQuat * pitchQuat; - playerphysics->ps.viewangles.x = 0; - playerphysics->ps.viewangles.z = 0; - playerphysics->ps.viewangles.y = both.getYaw().valueDegrees() *-1 + 90; + //playerphysics->ps.viewangles.z = both.getPitch().valueDegrees(); @@ -133,8 +129,7 @@ namespace MWWorld { Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - pm_ref.rightmove = -dir1.x; - pm_ref.forwardmove = dir1.z; + @@ -147,31 +142,24 @@ namespace MWWorld { Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - pm_ref.rightmove = -dir1.x; - pm_ref.forwardmove = dir1.z; + dir = 0.025*(quat*dir1); } - Pmove(playerphysics); + //set the walk direction act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); } - //mEngine->stepSimulation(duration); - Pmove(playerphysics); + mEngine->stepSimulation(duration); + std::vector< std::pair > response; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { btVector3 newPos = it->second->getPosition(); Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); - if(it->first == "player"){ - - coord = playerphysics->ps.origin; - //std::cout << "Coord" << coord << "\n"; - coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y - - } + response.push_back(std::pair(it->first, coord)); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index a2dea2492..b88ff23b1 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -5,7 +5,6 @@ #include #include #include "ptr.hpp" -#include namespace MWWorld { @@ -54,7 +53,7 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; - playerMove* playerphysics; + PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 37b97dd27..1972d8d5b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -31,7 +31,7 @@ const float WeatherGlobals::mThunderFrequency = .4; const float WeatherGlobals::mThunderThreshold = 0.6; const float WeatherGlobals::mThunderSoundDelay = 0.25; -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environment* env) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Environment* env) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) { @@ -268,8 +268,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environmen blight.mGlareView = 0; blight.mAmbientLoopSoundID = "blight"; mWeatherSettings["blight"] = blight; - - /* + Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; snow.mCloudsMaximumPercent = 1.0; @@ -326,7 +325,6 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, Environmen blizzard.mGlareView = 0; blizzard.mAmbientLoopSoundID = "BM Blizzard"; mWeatherSettings["blizzard"] = blizzard; - */ } void WeatherManager::setWeather(const String& weather, bool instant) @@ -508,32 +506,32 @@ void WeatherManager::update(float duration) float thunder = region->data.thunder/255.f; float ash = region->data.ash/255.f; float blight = region->data.blight/255.f; - //float snow = region->data.a/255.f; - //float blizzard = region->data.b/255.f; + float snow = region->data.a/255.f; + float blizzard = region->data.b/255.f; // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; srand(time(NULL)); float random = ((rand()%100)/100.f) * total; - //if (random > snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "blizzard"; - //else if (random > blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - // weather = "snow"; - /*else*/ if (random > ash+thunder+rain+overcast+foggy+cloudy+clear) + if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "blizzard"; + else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + weather = "snow"; + else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blight"; - else if (random > thunder+rain+overcast+foggy+cloudy+clear) + else if (random >= thunder+rain+overcast+foggy+cloudy+clear) weather = "ashstorm"; - else if (random > rain+overcast+foggy+cloudy+clear) + else if (random >= rain+overcast+foggy+cloudy+clear) weather = "thunderstorm"; - else if (random > overcast+foggy+cloudy+clear) + else if (random >= overcast+foggy+cloudy+clear) weather = "rain"; - else if (random > foggy+cloudy+clear) + else if (random >= foggy+cloudy+clear) weather = "overcast"; - else if (random > cloudy+clear) + else if (random >= cloudy+clear) weather = "foggy"; - else if (random > clear) + else if (random >= clear) weather = "cloudy"; else weather = "clear"; diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index a48cc7e72..a7252353d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -543,7 +543,7 @@ namespace MWWorld if (ptr==mPlayer->getPlayer()) { //std::cout << "X:" << ptr.getRefData().getPosition().pos[0] << " Z: " << ptr.getRefData().getPosition().pos[1] << "\n"; - + Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); if (currentCell) { @@ -750,15 +750,16 @@ namespace MWWorld // figure out which object we want to test against std::vector < std::pair < float, std::string > > results = mPhysics->getFacedObjects(); - // ignore the player - for (std::vector < std::pair < float, std::string > >::iterator it = results.begin(); - it != results.end(); ++it) + // ignore the player and other things we're not interested in + std::vector < std::pair < float, std::string > >::iterator it = results.begin(); + while (it != results.end()) { - if ( (*it).second == mPlayer->getPlayer().getRefData().getHandle() ) + if ( getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) { - results.erase(it); - break; + it = results.erase(it); } + else + ++it; } if (results.size() == 0) @@ -774,6 +775,10 @@ namespace MWWorld btVector3 p = mPhysics->getRayPoint(results.front().first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); + + //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; + //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; + query->occlusionTest(pos, node); } else @@ -786,8 +791,33 @@ namespace MWWorld btVector3 p = mPhysics->getRayPoint(results[1].first); Ogre::Vector3 pos(p.x(), p.z(), -p.y()); - Ogre::SceneNode* node = mFaced2.getRefData().getBaseNode(); - query->occlusionTest(pos, node); + Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); + Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); + + // no need to test if the first node is not occluder + if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) + { + mFacedHandle = mFaced1Name; + //std::cout << "node1 Not an occluder" << std::endl; + return; + } + + // no need to test if the second object is static (thus cannot be activated) + if (mFaced2.getTypeName().find("Static") != std::string::npos) + { + mFacedHandle = mFaced1Name; + return; + } + + // work around door problems + if (mFaced1.getTypeName().find("Static") != std::string::npos + && mFaced2.getTypeName().find("Door") != std::string::npos) + { + mFacedHandle = mFaced2Name; + return; + } + + query->occlusionTest(pos, node2); } } } @@ -834,6 +864,18 @@ namespace MWWorld return mRendering->getFader(); } + Ogre::Vector2 World::getNorthVector(Ptr::CellStore* cell) + { + ESMS::CellRefList statics = cell->statics; + ESMS::LiveCellRef* ref = statics.find("northmarker"); + if (!ref) + return Vector2(0, 1); + Ogre::SceneNode* node = ref->mData.getBaseNode(); + Vector3 dir = node->_getDerivedOrientation().yAxis(); + Vector2 d = Vector2(dir.x, dir.z); + return d; + } + void World::setWaterHeight(const float height) { mRendering->setWaterHeight(height); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 7f8b7e861..92540f82b 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -63,13 +63,14 @@ namespace MWWorld enum RenderMode { Render_CollisionDebug, - Render_Wireframe + Render_Wireframe, + Render_Pathgrid }; private: MWRender::RenderingManager* mRendering; - + MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; @@ -112,7 +113,7 @@ namespace MWWorld Environment& environment, const std::string& encoding); ~World(); - + OEngine::Render::Fader* getFader(); Ptr::CellStore *getExterior (int x, int y); @@ -121,7 +122,7 @@ namespace MWWorld void setWaterHeight(const float height); void toggleWater(); - + void adjustSky(); MWWorld::Player& getPlayer(); @@ -134,10 +135,13 @@ namespace MWWorld bool hasCellChanged() const; ///< Has the player moved to a different cell, since the last frame? - + bool isCellExterior() const; bool isCellQuasiExterior() const; + Ogre::Vector2 getNorthVector(Ptr::CellStore* cell); + ///< get north vector (OGRE coordinates) for given interior cell + Globals::Data& getGlobalVariable (const std::string& name); Globals::Data getGlobalVariable (const std::string& name) const; @@ -172,9 +176,9 @@ namespace MWWorld bool toggleSky(); ///< \return Resulting mode - + void changeWeather(const std::string& region, const unsigned int id); - + int getCurrentWeather() const; int getMasserPhase() const; diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 0e3563b26..fa197d960 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -79,7 +79,7 @@ class DirArchive: public Ogre::FileSystemArchive { passed = filename.substr(0, filename.length() - 2); } - if(filename.at(filename.length() - 2) == '>') + if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') passed = filename.substr(0, filename.length() - 6); copy = passed; } @@ -232,7 +232,7 @@ public: { passed = filename.substr(0, filename.length() - 2); } - if(filename.at(filename.length() - 2) == '>') + if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') passed = filename.substr(0, filename.length() - 6); // Open the file StreamPtr strm = narc->getFile(passed.c_str()); @@ -254,7 +254,7 @@ bool exists(const String& filename) { { passed = filename.substr(0, filename.length() - 2); } - if(filename.at(filename.length() - 2) == '>') + if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') passed = filename.substr(0, filename.length() - 6); return arc.exists(passed.c_str()); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2ab6ae621..616dd1daf 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1296,6 +1296,7 @@ void NIFLoader::loadResource(Resource *resource) char suffix = name.at(name.length() - 2); bool addAnim = true; bool hasAnim = false; + bool linkSkeleton = true; //bool baddin = false; bNiTri = true; if(name == "meshes\\base_anim.nif" || name == "meshes\\base_animkna.nif") @@ -1326,6 +1327,17 @@ void NIFLoader::loadResource(Resource *resource) addAnim = false; } + else if(suffix == ':') + { + //baddin = true; + linkSkeleton = false; + bNiTri = true; + std::string sub = name.substr(name.length() - 6, 4); + + if(sub.compare("0000") != 0) + addAnim = false; + + } switch(name.at(name.length() - 1)) { @@ -1464,7 +1476,7 @@ void NIFLoader::loadResource(Resource *resource) } //Don't link on npc parts to eliminate redundant skeletons //Will have to be changed later slightly for robes/skirts - if(triname == "") + if(linkSkeleton) mesh->_notifySkeleton(mSkel); } } diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp deleted file mode 100644 index 45fe84f4f..000000000 --- a/libs/openengine/bullet/pmove.cpp +++ /dev/null @@ -1,2042 +0,0 @@ -/* -This source file is a *modified* version of bg_pmove.c from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - - -#include "pmove.h" - - - -//#include "bprintf.h" - -//#include "..\..\ESMParser\ESMParser\CELL.h" - -//#include "GameTime.h" - -//#include "Object.h" - -//#include "Sound.h" - -//#include "..\..\ESMParser\ESMParser\SNDG.h" -//#include "..\..\ESMParser\ESMParser\SOUN.h" - -#include - -//SceneInstance* global_lastscene = NULL; - -// Forward declaration: -void PM_AirMove(); - -static playerMove* pm = NULL; - -//extern std::map ExtCellLookup; - -static struct playermoveLocal -{ - playermoveLocal() : frametime(1.0f / 20.0f), groundPlane(true), walking(true), msec(50) - { - forward = Ogre::Vector3(0.0f, 0.0f, 0.0f); - right = Ogre::Vector3(0.0f, 0.0f, 0.0f); - up = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - previous_origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - previous_velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - } - - traceResults groundTrace; - - //SceneInstance* scene; - - float frametime; // in seconds (usually something like 0.01f) - float impactSpeed; - - Ogre::Vector3 forward; - Ogre::Vector3 right; - Ogre::Vector3 up; - - int msec; - - Ogre::Vector3 previous_origin, previous_velocity; - - int previous_waterlevel; // the waterlevel before this pmove - - bool groundPlane; // if we're standing on a groundplane this frame - - bool walking; - int waterHeight; - bool hasWater; - bool isInterior; - //Object* traceObj; - -} pml; - -static inline void PM_ClipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - float backoff; - //float change; - //int i; - - // backoff = in dot normal - //backoff = DotProduct (in, normal); - backoff = in.dotProduct(normal); - - if ( backoff < 0 ) - backoff *= overbounce; - else - backoff /= overbounce; - - // change = normal * backoff - // out = in - change - /*for ( i=0 ; i<3 ; i++ ) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - }*/ - float changex = normal.x * backoff; - out.x = in.x - changex; - float changey = normal.y * backoff; - out.y = in.y - changey; - float changez = normal.z * backoff; - out.z = in.z - changez; -} - -float VectorNormalize2( const Ogre::Vector3& v, Ogre::Vector3& out) -{ - float length, ilength; - - length = v.x * v.x+ v.y * v.y + v.z * v.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x= v.x * ilength; - out.y = v.y * ilength; - out.z = v.z * ilength; - } else - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) ); -#endif - //VectorClear( out ); - out.x = 0; out.y = 0; out.z = 0; - } - - return length; - -} - - -float VectorNormalize(Ogre::Vector3& out) -{ - float length, ilength; - - length = out.x * out.x + out.y * out.y + out.z * out.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x = out.x * ilength; - out.y = out.y * ilength; - out.z = out.z * ilength; - } - - return length; - -} - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ - -bool PM_SlideMove( bool gravity ) -{ - int bumpcount, numbumps; - Ogre::Vector3 dir; - float d; - int numplanes; - Ogre::Vector3 planes[MAX_CLIP_PLANES]; - Ogre::Vector3 primal_velocity; - Ogre::Vector3 clipVelocity; - int i, j, k; - struct traceResults trace; - Ogre::Vector3 end; - float time_left; - float into; - Ogre::Vector3 endVelocity; - Ogre::Vector3 endClipVelocity; - - numbumps = 4; - - // primal_velocity = pm->ps->velocity - //VectorCopy (pm->ps->velocity, primal_velocity); - primal_velocity = pm->ps.velocity; - - if ( gravity ) - { - // endVelocity = pm->ps->velocity - vec3(0, 0, pm->ps->gravity * pml.frametime) - //VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity = pm->ps.velocity; - //endVelocity[2] -= pm->ps->gravity * pml.frametime; - endVelocity.y -= pm->ps.gravity * pml.frametime; - - // pm->ps->velocity = avg(pm->ps->velocity.z, endVelocity.z) - //pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - pm->ps.velocity.y= (pm->ps.velocity.y + endVelocity.y) * 0.5f; - - //primal_velocity[2] = endVelocity[2]; - primal_velocity.y = endVelocity.y; - - if ( pml.groundPlane ) - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) - { - numplanes = 1; - - // planes[0] = pml.groundTrace.plane.normal - //VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - planes[0] = pml.groundTrace.planenormal; - } else - numplanes = 0; - - // never turn against original velocity - VectorNormalize2( pm->ps.velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) - { - - // calculate position we are trying to move to - //VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - end = pm->ps.origin + pm->ps.velocity * time_left; - - // see if we can make it there - //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, end, halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if (trace.allsolid) - { - // entity is completely trapped in another solid - //pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - pm->ps.velocity.y = 0; - return true; - } - - if (trace.fraction > 0) - // actually covered some distance - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact8 - //PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) - { - // this shouldn't really happen - //VectorClear( pm->ps->velocity ); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) - { - if (trace.planenormal.dotProduct(planes[i]) > 0.99) //OGRE::VECTOR3 ? - //if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) - { - // pm->ps->velocity += (trace.plane.normal + pm->ps->velocity) - //VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - pm->ps.velocity = (trace.planenormal + pm->ps.velocity); - break; - } - } - - if ( i < numplanes ) - continue; - - //VectorCopy (trace.plane.normal, planes[numplanes]); - planes[numplanes] = trace.planenormal; - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) - { - //into = DotProduct( pm->ps->velocity, planes[i] ); - into = pm->ps.velocity.dotProduct(planes[i]); - if ( into >= 0.1 ) - continue; // move doesn't interact with the plane - - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) - pml.impactSpeed = -into; - - // slide along the plane - //PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, planes[i], clipVelocity, OVERCLIP); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) - { - if ( j == i ) - continue; - - if (clipVelocity.dotProduct(planes[j]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if (clipVelocity.dotProduct(planes[i]) >= 0) - //if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) - continue; - - - // slide the original velocity along the crease - //dProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, pm->ps->velocity ); - d = dir.dotProduct(pm->ps.velocity); - - //VectorScale( dir, d, clipVelocity ); - clipVelocity = dir * d; - - //CrossProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, endVelocity ); - d = dir.dotProduct(endVelocity); - - //VectorScale( dir, d, endClipVelocity ); - endClipVelocity = dir * d; - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) - { - if ( k == i || k == j ) - continue; - - if (clipVelocity.dotProduct(planes[k]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - // stop dead at a tripple plane interaction - //VectorClear( pm->ps->velocity ); - printf("Stop dead at a triple plane interaction\n"); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - } - - // if we have fixed all interactions, try another move - //VectorCopy( clipVelocity, pm->ps->velocity ); - pm->ps.velocity = clipVelocity; - - //VectorCopy( endClipVelocity, endVelocity ); - endVelocity = endClipVelocity; - break; - } - } - - if ( gravity ) - //VectorCopy( endVelocity, pm->ps->velocity ); - pm->ps.velocity = endVelocity; - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps.pm_time ) - //VectorCopy( primal_velocity, pm->ps->velocity ); - pm->ps.velocity = primal_velocity; - - //return ( (qboolean)(bumpcount != 0) ); - return bumpcount != 0; -} - -/* -================== -PM_StepSlideMove - -================== -*/ -int PM_StepSlideMove( bool gravity ) -{ - Ogre::Vector3 start_o, start_v; - Ogre::Vector3 down_o, down_v; - traceResults trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - Ogre::Vector3 up, down; - float stepSize; - - // start_o = pm->ps->origin - //VectorCopy (pm->ps->origin, start_o); - start_o = pm->ps.origin; - - // start_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, start_v); - start_v = pm->ps.velocity; - - if ( PM_SlideMove( gravity ) == false ) - return 1; // we got exactly where we wanted to go first try - - // down = start_o - vec3(0, 0, STEPSIZE) - //VectorCopy(start_o, down); - down = start_o; - down.y -= STEPSIZE; - - //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, start_o, down, , 0, pml.scene); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, down, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - // up = vec3(0, 0, 1) - //VectorSet(up, 0, 0, 1); - up = Ogre::Vector3(0.0f, 1.0f, 0.0f); - - // never step up when you still have up velocity - //if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) - if (pm->ps.velocity.y > 0 && ( - trace.fraction == 1.0 || trace.planenormal.dotProduct(up) < 0.7 - ) ) - return 2; - - // down_o = pm->ps->origin - //VectorCopy (pm->ps->origin, down_o); - down_o = pm->ps.origin; - - // down_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, down_v); - down_v = pm->ps.velocity; - - // up = start_o + vec3(0, 0, STEPSIZE) - //VectorCopy (start_o, up); - up = start_o; - //up[2] += STEPSIZE; - up.y += STEPSIZE; - - // test the player position if they were a stepheight higher - //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&up, D3DXVECTOR3(0.0f, STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, up, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.allsolid ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:bend can't step\n", c_pmove); - //bprintf("bend can't step\n"); - return 3; // can't step up - } - - //stepSize = trace.endpos[2] - start_o[2]; - stepSize = trace.endpos.y - start_o.y; - - // try slidemove from this position - //VectorCopy (trace.endpos, pm->ps->origin); // pm->ps->origin = trace.endpos - pm->ps.origin = trace.endpos; - //VectorCopy (start_v, pm->ps->velocity); // pm->ps->velocity = start_v - pm->ps.velocity = start_v; - - PM_SlideMove( gravity ); - - // push down the final amount - - // down = pm->ps->origin - vec3(0, 0, stepSize) - //VectorCopy (pm->ps->origin, down); - down = pm->ps.origin; - //down[2] -= stepSize; - down.y -= stepSize; - - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, down, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( !trace.allsolid ) - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if ( trace.fraction < 1.0 ) - //PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, trace.planenormal, pm->ps.velocity, OVERCLIP); - - { - // use the step move - float delta; - - //delta = pm->ps->origin[2] - start_o[2]; - delta = pm->ps.origin.y - start_o.y; - if ( delta > 2 ) - { - if (gravity) - printf("g on: %f ", delta); - else - printf("g off: %f ", delta); - - if ( delta < 7 ) - printf("stepped 3 < x < 7\n"); - //PM_AddEvent( EV_STEP_4 ); - else if ( delta < 11 ) - printf("stepped 7 < x < 11\n"); - //PM_AddEvent( EV_STEP_8 ); - else if ( delta < 15 ) - printf("stepped 11 < x < 15\n"); - //PM_AddEvent( EV_STEP_12 ); - else - printf("stepped 15+\n"); - //PM_AddEvent( EV_STEP_16 ); - - } - /*if ( pm->debugLevel ) - Com_Printf("%i:stepped\n", c_pmove);*/ - } - - return 4; -} - -void PM_Friction(void) -{ - Ogre::Vector3 vec; - float* vel; - float speed, newspeed, control; - float drop; - - vel = &(pm->ps.velocity.x); - - // vec = vel - //VectorCopy( vel, vec ); - vec = pm->ps.velocity; - - if ( pml.walking ) - //vec[2] = 0; // ignore slope movement - vec.y = 0; - - //speed = VectorLength(vec); - speed = vec.length(); - if (speed < 1) - { - vel[0] = 0; - vel[2] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - //bprintf("Static friction (vec = [%f, %f, %f]) (vec.length = %f)\n", vec.x, vec.y, vec.z, speed); - return; - } - - drop = 0; - - // apply ground friction - if ( pm->ps.waterlevel <= 1 ) - { - if ( pml.walking )//&& !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) - { - // if getting knocked back, no friction - //if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) - { - control = (speed < pm_stopspeed) ? pm_stopspeed : speed; - drop += control * pm_friction * pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->ps.waterlevel ) - drop += speed * pm_waterfriction * pm->ps.waterlevel * pml.frametime; - - // apply flying friction - /*if ( pm->ps->powerups[PW_FLIGHT]) - drop += speed * pm_flightfriction * pml.frametime; - - if ( pm->ps->pm_type == PM_SPECTATOR) - drop += speed * pm_spectatorfriction * pml.frametime;*/ - if (pm->ps.move_type == PM_SPECTATOR) - drop += speed * pm_flightfriction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - newspeed /= speed; - - // vel *= newspeed - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; -} - -float PM_CmdScale(playerMove::playercmd* const cmd) -{ - int max; - float total; - float scale; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) - max = abs( cmd->rightmove ); - - if ( abs( cmd->upmove ) > max ) - max = abs( cmd->upmove ); - - if ( !max ) - return 0; - - total = sqrtf( (const float)(cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); - scale = (float)pm->ps.speed * max / ( 127.0f * total ); - - return scale; -} - -static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel ) -{ -// int i; - float addspeed, accelspeed, currentspeed; - - // currentspeed = pm->ps->velocity dot wishdir - //currentspeed = DotProduct (pm->ps->velocity, wishdir); - currentspeed = pm->ps.velocity.dotProduct(wishdir); - - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = accel * pml.frametime * wishspeed; - - // Clamp accelspeed at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // pm->ps->velocity += accelspeed * wishdir - //for (i=0 ; i<3 ; i++) - //pm->ps->velocity[i] += accelspeed * wishdir[i]; - pm->ps.velocity += (wishdir * accelspeed); -} - -static bool PM_CheckJump(void) -{ - //if ( pm->ps->pm_flags & PMF_RESPAWNED ) - //return qfalse; // don't allow jump until all buttons are up - - if ( pm->cmd.upmove < 10 ) - // not holding jump - return false; - - pm->cmd.upmove = 0; - - // must wait for jump to be released - /*if ( pm->ps->pm_flags & PMF_JUMP_HELD ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return false; - }*/ - - pml.groundPlane = false; // jumping away - pml.walking = false; - //pm->ps->pm_flags |= PMF_JUMP_HELD; - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.y = JUMP_VELOCITY; - //PM_AddEvent( EV_JUMP ); - - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - - return true; -} - -static void PM_WaterMove( playerMove* const pm ) -{ - //int i; - //vec3_t wishvel; - Ogre::Vector3 wishvel; - float wishspeed; - //vec3_t wishdir; - Ogre::Vector3 wishdir; - float scale; - float vel; - - /*if ( PM_CheckWaterJump() ) - { - PM_WaterJumpMove(); - return; - }*/ -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - if (pm->cmd.forwardmove || pm->cmd.rightmove) - { - //NEEDS TO BE REWRITTEN FOR OGRE TIME--------------------------------------------------- - /* - static const TimeTicks footstep_duration = GetTimeFreq(); // make each splash last 1.0s - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pm->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // splashes while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - //-----------------jhooks1 - - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_swim : SNDG::l_swim); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - //Sound, ignore for now -- jhooks1 - //} - } - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - */ - wishvel.x = 0; - wishvel.y = -60; - wishvel.z = 0; - } - else - { - /*for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;*/ - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.y += pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps.speed * pm_swimScale ) - wishspeed = pm->ps.speed * pm_swimScale; - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - //if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) - if (pml.groundPlane && pm->ps.velocity.dotProduct(pml.groundTrace.planenormal) < 0.0f) - { - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - - VectorNormalize(pm->ps.velocity); - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - } - - PM_SlideMove( false ); -} - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( playerMove* const pmove ) -{ -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - float accelerate; - float vel; - - if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) - { - // begin swimming - PM_WaterMove(pmove); - return; - } - - - if ( PM_CheckJump () ) - { - // jumped away - if ( pm->ps.waterlevel > 1 ) - PM_WaterMove(pmove); - else - PM_AirMove(); - printf("Jumped away\n"); - return; - } - - // Footsteps time - if (pmove->cmd.forwardmove || pmove->cmd.rightmove) - { - bool step_underwater = false; - //if (pmove->traceObj) - //{ - - - //jhooks1 - Water handling, deal with later - - - - if (pmove->hasWater) - { - if (pmove->hasWater ) - { - const float waterHeight = pmove->waterHeight; - const float waterSoundStepHeight = waterHeight + halfExtents.y; - if (pmove->ps.origin.y < waterSoundStepHeight) - step_underwater = true; - } - } - //} - - /* - static const TimeTicks footstep_duration = GetTimeFreq() / 2; // make each footstep last 500ms - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pmove->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // footsteps while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - - if (step_underwater) - { - /* - const namestruct ns(lastWasLeft ? "FootWaterRight" : "FootWaterLeft"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - else - { - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_foot : SNDG::l_foot); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - - PM_Friction (); - - //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.y = 0; - - //pml.right[2] = 0; - pml.right.y = 0; - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); - // - //VectorNormalize (pml.forward); - pml.forward = pml.forward.normalise(); - pml.right = pml.right.normalise(); - - - // wishvel = (pml.forward * fmove) + (pml.right * smove); - //for ( i = 0 ; i < 3 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); - - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - // wishdir = wishvel - //VectorCopy (wishvel, wishdir); - //wishvel = wishdir; - wishdir = wishvel; - - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - // clamp the speed lower if ducking - if ( pm->cmd.ducking ) - if ( wishspeed > pm->ps.speed * pm_duckScale ) - wishspeed = pm->ps.speed * pm_duckScale; - - // clamp the speed lower if wading or walking on the bottom - if ( pm->ps.waterlevel ) - { - float waterScale; - - waterScale = pm->ps.waterlevel / 3.0f; - waterScale = 1.0f - ( 1.0f - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps.speed * waterScale ) - wishspeed = pm->ps.speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //accelerate = pm_airaccelerate; - //else - accelerate = pm_accelerate; - - - PM_Accelerate (wishdir, wishspeed, accelerate); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - //else - //{ - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - //} - - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - - // slide along the ground plane - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, - pm->ps.velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - //VectorNormalize(pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity.normalise(); - - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - - // don't do anything if standing still - //if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) - if (!pm->ps.velocity.x && !pm->ps.velocity.z) - return; - - PM_StepSlideMove( false ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - -void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::playercmd* const cmd ) -{ - short temp; - int i; - - //while(1); - - //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) - //return; // no view changes at all - - //if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) - //return; // no view changes at all - - // circularly clamp the angles with deltas - //bprintf("View angles: %i, %i, %i\n", cmd->angles[0], cmd->angles[1], cmd->angles[2]); - for (i = 0 ; i < 3 ; i++) - { - temp = cmd->angles[i];// + ps->delta_angles[i]; - //if ( i == PITCH ) - { - // don't let the player look up or down more than 90 degrees - /*if ( temp > 16000 ) - { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp = 16000; - } - else if ( temp < -16000 ) - { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp = -16000; - }*/ - } - (&(ps->viewangles.x) )[i] = SHORT2ANGLE(temp); - //cmd->angles[i] += ps->delta_angles[i]; - } - //ps->delta_angles[0] = ps->delta_angles[1] = ps->delta_angles[2] = 0; - -} - -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) -{ - float angle; - static float sr, sp, sy, cr, cp, cy; - // static to help MS compiler fp bugs - - //angle = angles[YAW] * (M_PI*2 / 360); - angle = angles.x * (M_PI * 2.0f / 360.0f); - sp = sinf(angle); - cp = cosf(angle); - - //angle = angles[PITCH] * (M_PI*2 / 360); - angle = angles.y * (-M_PI * 2.0f / 360.0f); - sy = sinf(angle); - cy = cosf(angle); - - //angle = angles[ROLL] * (M_PI*2 / 360); - angle = angles.z * (M_PI * 2.0f / 360.0f); - sr = sinf(angle); - cr = cosf(angle); - - if (forward) - { - forward->x = cp * cy; - forward->z = cp * sy; - forward->y = -sp; - } - if (right) - { - right->x = (-1 * sr * sp * cy + -1 * cr * -sy); - right->z = (-1 * sr * sp * sy + -1 * cr * cy); - right->y = 0.0f;//-1 * sp * cp; - } - if (up) - { - up->x = (cr * sp * cy + -sr * -sy); - up->z = (cr * sp * sy + -sr * cy); - up->y = cr * cp; - } -} - -void PM_GroundTraceMissed() -{ - traceResults trace; - Ogre::Vector3 point; - - if ( pm->ps.groundEntityNum != ENTITYNUM_NONE ) - { - // we just transitioned into freefall - //if ( pm->debugLevel ) - //Com_Printf("%i:lift\n", c_pmove); - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - //VectorCopy( pm->ps->origin, point ); - point = pm->ps.origin; - //point[2] -= 64; - point.y -= 64; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.fraction == 1.0 ) - { - if ( pm->cmd.forwardmove >= 0 ) - { - //PM_ForceLegsAnim( LEGS_JUMP ); - //pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - //PM_ForceLegsAnim( LEGS_JUMPB ); - //pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - } - } - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; -} - -static bool PM_CorrectAllSolid(traceResults* const trace) -{ - int i, j, k; - Ogre::Vector3 point; - std::cout << "Correct all solid\n"; - - //if ( pm->debugLevel ) - //Com_Printf("%i:allsolid\n", c_pmove); - //bprintf("allsolid\n"); - - // jitter around - for (i = -1; i <= 1; i++) - { - for (j = -1; j <= 1; j++) - { - for (k = -1; k <= 1; k++) - { - //VectorCopy(pm->ps->origin, point); - point = pm->ps.origin; - - /*point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k;*/ - point += Ogre::Vector3( (const float)i, (const float)j, (const float)k); - - //pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&point, *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0, pml.traceObj); - newtrace(trace, point, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if ( !trace->allsolid ) - { - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.y -= 0.25f; - - //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = *trace; - return true; - } - } - } - } - - //pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - - return false; -} - -static void PM_CrashLand( void ) -{ - float delta; - float dist ; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) - PM_ForceLegsAnim( LEGS_LANDB ); - else - PM_ForceLegsAnim( LEGS_LAND ); - - pm->ps->legsTimer = TIMER_LAND;*/ - - // calculate the exact velocity on landing - //dist = pm->ps->origin[2] - pml.previous_origin[2]; - - dist = pm->ps.origin.y - pml.previous_origin.y; - - //vel = pml.previous_velocity[2]; - vel = pml.previous_velocity.y; - - //acc = -pm->ps->gravity; - acc = -pm->ps.gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) - return; - - t = (-b - sqrtf( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta * delta * 0.0001f; - - // ducking while falling doubles damage - /*if ( pm->ps->pm_flags & PMF_DUCKED ) - delta *= 2;*/ - if (pm->cmd.upmove < -20) - delta *= 2; - - // never take falling damage if completely underwater - if ( pm->ps.waterlevel == 3 ) - return; - - // reduce falling damage if there is standing water - if ( pm->ps.waterlevel == 2 ) - delta *= 0.25; - if ( pm->ps.waterlevel == 1 ) - delta *= 0.5; - - if ( delta < 1 ) - return; - - if (delta > 60) - printf("Far crashland: %f\n", delta); - else if (delta > 40) - printf("Medium crashland: %f\n", delta); - else if (delta > 4) - printf("Short crashland: %f\n", delta); - - if (delta > 60) - { - /* - static const namestruct healthDamage("Health Damage"); - const SOUN* const soun = SOUN::GetSound(healthDamage); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - - if (delta > 3) // We need at least a short crashland to proc the sound effects: - { - bool splashSound = false; - - if (pm->hasWater) - { - - const float waterHeight = pm->waterHeight; - const float waterHeightSplash = waterHeight + halfExtents.y; - if (pm->ps.origin.y < waterHeightSplash) - { - splashSound = true; - } - - } - - - if (splashSound) - { - //Change this later----------------------------------- - /* - const namestruct ns("DefaultLandWater"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundDatga->GetVolumeFloat() ); - }*/ - } - else - { - //Change this later--------------------------------- - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, SNDG::land); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - //if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) - { - /*if ( delta > 60 ) - PM_AddEvent( EV_FALL_FAR ); - else if ( delta > 40 ) - { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) - PM_AddEvent( EV_FALL_MEDIUM ); - } - else if ( delta > 7 ) - PM_AddEvent( EV_FALL_SHORT ); - else - PM_AddEvent( PM_FootstepForSurface() );*/ - } - - // start footstep cycle over - //pm->ps->bobCycle = 0; -} - -static void PM_GroundTrace( void ) -{ - std::cout << "Ground trace\n"; - Ogre::Vector3 point; - traceResults trace; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.y -= 0.25f; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - //std::cout << "ALL SOLID\n"; - if ( !PM_CorrectAllSolid(&trace) ){ - //std::cout << "Returning after correct all solid\n"; - return; - } - } - - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0 ) - { - PM_GroundTraceMissed(); - pml.groundPlane = false; - pml.walking = false; - return; - } - - // check if getting thrown off the ground - //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.y > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:kickoff\n", c_pmove); - - // go into jump animation - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - return; - } - - // slopes that are too steep will not be considered onground - //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) - if (trace.planenormal.y < MIN_WALK_NORMAL) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:steep\n", c_pmove); - - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = true; - pml.walking = false; - return; - } - - pml.groundPlane = true; - pml.walking = true; - - // hitting solid ground will end a waterjump - /*if (pm->ps.pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - }*/ - - if ( pm->ps.groundEntityNum == ENTITYNUM_NONE ) - { - // just hit the ground - /*if ( pm->debugLevel ) - Com_Printf("%i:Land\n", c_pmove);*/ - //bprintf("Land\n"); - - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - //if ( pml.previous_velocity[2] < -200 ) - if (pml.previous_velocity.y < -200) - { - // don't allow another jump for a little while - //pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps.pm_time = 250; - } - } - - pm->ps.groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - //PM_AddTouchEnt( trace.entityNum ); -} - -static void PM_AirMove() -{ - //int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.y = 0; - //pml.right[2] = 0; - pml.right.y = 0; - //VectorNormalize (pml.forward); - pml.forward = Ogre::Vector3(pml.forward.normalise()); - pml.right = Ogre::Vector3(pml.right.normalise()); - //VectorNormalize (pml.right); - - //for ( i = 0 ; i < 2 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - //wishvel[2] = 0; - wishvel.y = 0; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); - -/*#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif*/ - - /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; -} - -static void PM_NoclipMove( void ) -{ - float speed, drop, friction, control, newspeed; -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - - //pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - //speed = VectorLength (pm->ps->velocity); - speed = pm->ps.velocity.length(); - if (speed < 1) - //VectorCopy (vec3_origin, pm->ps->velocity); - pm->ps.velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - //VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * newspeed; - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - //for (i=0 ; i<3 ; i++) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - //wishvel[2] += pm->cmd.upmove; - wishvel.y += pm->cmd.upmove; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - //VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); - pm->ps.origin = pm->ps.origin + pm->ps.velocity * pml.frametime; -} - -static void PM_DropTimers( void ) -{ - // drop misc timing counter - if ( pm->ps.pm_time ) - { - if ( pml.msec >= pm->ps.pm_time ) - { - //pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps.pm_time = 0; - } - else - pm->ps.pm_time -= pml.msec; - } - - //bprintf("Time: %i\n", pm->ps.pm_time); - - // drop animation counter - /*if ( pm->ps->legsTimer > 0 ) - { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) - pm->ps->legsTimer = 0; - } - - if ( pm->ps->torsoTimer > 0 ) - { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) - pm->ps->torsoTimer = 0; - }*/ -} - -static void PM_FlyMove( void ) -{ - //int i; - Ogre::Vector3 wishvel; - float wishspeed; - Ogre::Vector3 wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0;*/ - wishvel = Ogre::Vector3(0,0,0); - } - else - { - //for (i=0 ; i<3 ; i++) - //wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.y += /*6.35f * */pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( false ); -} - - -void PM_SetWaterLevel( playerMove* const pm ) -{ - Ogre::Vector3 point; - //int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - - pm->ps.waterlevel = WL_DRYLAND; - pm->ps.watertype = 0; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; */ - point.x = pm->ps.origin.x; - point.y = pm->ps.origin.y + MINS_Z + 1; - point.z = pm->ps.origin.z; - - //cont = pm->pointcontents( point, pm->ps->clientNum ); - bool checkWater = (pml.hasWater && pml.waterHeight > point.y); - //if ( cont & MASK_WATER ) - if ( checkWater) - { - sample2 = /*pm->ps.viewheight*/DEFAULT_VIEWHEIGHT - MINS_Z; - sample1 = sample2 / 2; - - pm->ps.watertype = CONTENTS_WATER;//cont; - pm->ps.waterlevel = WL_ANKLE; - //point[2] = pm->ps->origin[2] + MINS_Z + sample1; - point.y = pm->ps.origin.y + MINS_Z + sample1; - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - if (checkWater) - { - pm->ps.waterlevel = WL_WAIST; - //point[2] = pm->ps->origin[2] + MINS_Z + sample2; - point.y = pm->ps.origin.y + MINS_Z + sample2; - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - if (checkWater ) - pm->ps.waterlevel = WL_UNDERWATER; - } - } -} - -void PmoveSingle (playerMove* const pmove) -{ - std::cout << "Pmove single\n"; - //pm = pmove; - - // Aedra doesn't support Q3-style VM traps D: //while(1); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - //c_pmove++; - - // clear results - //pm->numtouch = 0; - pm->ps.watertype = 0; - pm->ps.waterlevel = WL_DRYLAND; - - //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) - //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - //if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) - //pm->cmd.buttons &= ~BUTTON_WALKING; - - - // set the talk balloon flag - //if ( pm->cmd.buttons & BUTTON_TALK ) - //pm->ps->eFlags |= EF_TALK; - //else - //pm->ps->eFlags &= ~EF_TALK; - - // set the firing flag for continuous beam weapons - /*if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) - pm->ps->eFlags |= EF_FIRING; - else - pm->ps->eFlags &= ~EF_FIRING;*/ - - // clear the respawned flag if attack and use are cleared - /*if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) - pm->ps->pm_flags &= ~PMF_RESPAWNED;*/ - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - /*if ( pmove->cmd.buttons & BUTTON_TALK ) - { - // keep the talk button set tho for when the cmd.serverTime > 66 msec - // and the same cmd is used multiple times in Pmove - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - }*/ - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml) ); - - // Aedra-specific code: - //pml.scene = global_lastscene; - - - // End Aedra-specific code - pml.hasWater = pmove->hasWater; - pml.isInterior = pmove->isInterior; - pml.waterHeight = pmove->waterHeight; -#ifdef _DEBUG - if (!pml.traceObj) - __debugbreak(); - - if (!pml.traceObj->incellptr) - __debugbreak(); -#endif - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; - if ( pml.msec < 1 ) - pml.msec = 1; - else if ( pml.msec > 200 ) - pml.msec = 200; - - //pm->ps->commandTime = pmove->cmd.serverTime; - - // Commented out as a hack - pm->ps.commandTime = pmove->cmd.serverTime; - - // Handle state change procs: - if (pm->cmd.activating != pm->cmd.lastActivatingState) - { - if (!pm->cmd.lastActivatingState && pm->cmd.activating) - pm->cmd.procActivating = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procActivating = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procActivating = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastActivatingState = pm->cmd.activating; - - if (pm->cmd.dropping != pm->cmd.lastDroppingState) - { - if (!pm->cmd.lastDroppingState && pm->cmd.dropping) - pm->cmd.procDropping = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procDropping = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procDropping = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastDroppingState = pm->cmd.dropping; - - // save old org in case we get stuck - //VectorCopy (pm->ps->origin, pml.previous_origin); - pml.previous_origin = pm->ps.origin; - - // Copy over the lastframe origin - pmove->ps.lastframe_origin = pmove->ps.origin; - - //pmove->ps.lastframe_origin = pmove->ps.origin; - - // save old velocity for crashlanding - //VectorCopy (pm->ps->velocity, pml.previous_velocity); - pml.previous_velocity = pm->ps.velocity; - - pml.frametime = pml.msec * 0.001f; - - // update the viewangles - //PM_UpdateViewAngles( &(pm->ps), &(pm->cmd) ); - - AngleVectors (pm->ps.viewangles, &(pml.forward), &(pml.right), &(pml.up) ); - - //if ( pm->cmd.upmove < 10 ) - // not holding jump - //pm->ps->pm_flags &= ~PMF_JUMP_HELD; - - // decide if backpedaling animations should be used - /*if ( pm->cmd.forwardmove < 0 ) - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;*/ - - /*if ( pm->ps->pm_type >= PM_DEAD ) - { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - }*/ - - if ( pm->ps.move_type == PM_SPECTATOR ) - { - std::cout << "SPECTATOR\n"; - //PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps.move_type == PM_NOCLIP ) - { - std::cout << "NOCLIP\n"; - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps.move_type == PM_FREEZE){ - std::cout << "FREEZE\n"; - return; // no movement at all - - } - - if ( pm->ps.move_type == PM_INTERMISSION || pm->ps.move_type == PM_SPINTERMISSION){ - std::cout << "INTERMISSION\n"; - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(pmove); - pml.previous_waterlevel = pmove->ps.waterlevel; - - // set mins, maxs, and viewheight - //PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - - /*if ( pm->ps->pm_type == PM_DEAD ) - PM_DeadMove (); - - PM_DropTimers();*/ - - PM_DropTimers(); - -/*#ifdef MISSIONPACK - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_InvulnerabilityMove(); - } else -#endif*/ - /*if ( pm->ps->powerups[PW_FLIGHT] ) - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } - else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - PM_WaterJumpMove();*/ - if ( pmove->ps.waterlevel > 1 ) - // swimming - PM_WaterMove(pmove); - else if ( pml.walking ) - { - std::cout << "WALKING\n"; - // walking on ground - PM_WalkMove(pmove); - //bprintf("WalkMove\n"); - } - else - { - // airborne - std::cout << "AIRMOVE\n"; - PM_AirMove(); - //bprintf("AirMove\n"); - } - - //PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - PM_SetWaterLevel(pmove); - - // weapons - /*PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity );*/ -} - -void Ext_UpdateViewAngles(playerMove* const pm) -{ - playerMove::playerStruct* const ps = &(pm->ps); - playerMove::playercmd* const cmd = &(pm->cmd); - PM_UpdateViewAngles(ps, cmd); -} - -void Pmove (playerMove* const pmove) -{ - pm = pmove; - - int finalTime; - - finalTime = pmove->cmd.serverTime; - - pmove->ps.commandTime = 40; - - if ( finalTime < pmove->ps.commandTime ) - return; // should not happen - - if ( finalTime > pmove->ps.commandTime + 1000 ) - pmove->ps.commandTime = finalTime - 1000; - - pmove->ps.pmove_framecount = (pmove->ps.pmove_framecount + 1) & ( (1 << PS_PMOVEFRAMECOUNTBITS) - 1); - - // chop the move up if it is too long, to prevent framerate - // dependent behavior - while ( pmove->ps.commandTime != finalTime ) - { - int msec; - - msec = finalTime - pmove->ps.commandTime; - - if ( pmove->pmove_fixed ) - if ( msec > pmove->pmove_msec ) - msec = pmove->pmove_msec; - else - if ( msec > 66 ) - msec = 66; - - pmove->cmd.serverTime = pmove->ps.commandTime + msec; - - if (pmove->isInterior) - { - PmoveSingle( pmove ); - } - else - { - PmoveSingle( pmove ); - /* - std::map::const_iterator it = ExtCellLookup.find(PositionToCell(pmove->ps.origin) ); - if (it != ExtCellLookup.end() ) - { - pmove->traceObj->incellptr = it->second; - }*/ - } - - //if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) - //pmove->cmd.upmove = 20; - } - - //pmove->ps.last_compute_time = GetTimeQPC(); - //pmove->ps.lerp_multiplier = (pmove->ps.origin - pmove->ps.lastframe_origin);// * (1.000 / 31.0); - - //PM_CheckStuck(); - -} - - diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h deleted file mode 100644 index e90cc3b35..000000000 --- a/libs/openengine/bullet/pmove.h +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef OENGINE_BULLET_PMOVE_H -#define OENGINE_BULLET_PMOVE_H -/* -This source file is a *modified* version of various header files from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - -#include -#include -#include -#include "trace.h" -#include "physic.hpp" - - -//#include "GameMath.h" -//#include "GameTime.h" - -// Forwards-declare it! - -/*#ifndef COMPILING_PMOVE -#include "Scene.h" -extern SceneInstance* global_lastscene; -#endif*/ - -static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); - -#define MAX_CLIP_PLANES 5 -#define OVERCLIP 1.001f -//#define STEPSIZE 18 // 18 is way too much -#define STEPSIZE (18 / 2) -#ifndef M_PI - #define M_PI 3.14159265358979323846f -#endif -#define YAW 0 -#define PITCH /*1*/2 -#define ROLL /*2*/1 -#define SHORT2ANGLE(x) ( (x) * (360.0f / 65536.0f) ) -#define ANGLE2SHORT(x) ( (const short)( (x) / (360.0f / 65536.0f) ) ) -#define GENTITYNUM_BITS 10 // don't need to send any more -#define MAX_GENTITIES (1 << GENTITYNUM_BITS) -#define ENTITYNUM_NONE (MAX_GENTITIES - 1) -#define ENTITYNUM_WORLD (MAX_GENTITIES - 2) -#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes -#define JUMP_VELOCITY (270 * 1) -#define PS_PMOVEFRAMECOUNTBITS 6 -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT (-16) -#define CONTENTS_SOLID 1 // an eye is never valid in a solid -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_FOG 64 -static const float pm_accelerate = 10.0f; -static const float pm_stopspeed = 100.0f; -static const float pm_friction = 6.0f; -static const float pm_flightfriction = 3.0f; -static const float pm_waterfriction = 1.0f; -static const float pm_airaccelerate = 1.0f; -static const float pm_swimScale = 0.50f; -static const float pm_duckScale = 0.25f; -static const float pm_flyaccelerate = 8.0f; -static const float pm_wateraccelerate = 4.0f; - -enum pmtype_t : unsigned char -{ - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -}; - -enum waterlevel_t : unsigned char -{ - WL_DRYLAND = 0, - WL_ANKLE, - WL_WAIST, - WL_UNDERWATER -}; - - -//#include "bprintf.h" - -struct playerMove -{ - struct playerStruct - { - playerStruct() : gravity(50.0f), speed(320.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NORMAL), pm_time(0) - { - origin = Ogre::Vector3(733.164f,1000.0f, 839.432f); - velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - delta_angles[0] = delta_angles[1] = delta_angles[2] = 0; - - lastframe_origin.x = lastframe_origin.y = lastframe_origin.z = 0; - lerp_multiplier.x = lerp_multiplier.y = lerp_multiplier.z = 0; - } - - inline void SpeedUp(void) - { - printf("speed up to: %f\n", speed); - speed *= 1.25f; - } - - inline void SpeedDown(void) - { - printf("speed down to %f\n", speed); - speed /= 1.25f; - } - - Ogre::Vector3 velocity; - Ogre::Vector3 origin; - float gravity; // default = 800 - float speed; // default = 320 - - int commandTime; // the time at which this command was issued (in milliseconds) - - int pm_time; - - Ogre::Vector3 viewangles; - - int groundEntityNum; - - int pmove_framecount; - - int watertype; - waterlevel_t waterlevel; - - signed short delta_angles[3]; - - pmtype_t move_type; - - float last_compute_time; - Ogre::Vector3 lastframe_origin; - Ogre::Vector3 lerp_multiplier; - } ps; - - struct playercmd - { - enum CMDstateChange - { - NO_CHANGE, - KEYDOWN, - KEYUP - }; - - playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), - activating(false), lastActivatingState(false), procActivating(NO_CHANGE), - dropping(false), lastDroppingState(false), procDropping(NO_CHANGE) - { - angles[0] = angles[1] = angles[2] = 0; - } - - int serverTime; - - short angles[3]; - - signed char forwardmove; - signed char rightmove; - signed char upmove; - - bool ducking; - bool activating; // if the user is holding down the activate button - bool dropping; // if the user is dropping an item - - bool lastActivatingState; - bool lastDroppingState; - - CMDstateChange procActivating; - CMDstateChange procDropping; - } cmd; - - playerMove() : msec(50), pmove_fixed(false), pmove_msec(50), waterHeight(0), isInterior(true), hasWater(false) - { - } - - int msec; - int pmove_msec; - bool pmove_fixed; - int waterHeight; - bool hasWater; - bool isInterior; - //Object* traceObj; - OEngine::Physic::PhysicEngine* mEngine; -}; - -void Pmove (playerMove* const pmove); -void Ext_UpdateViewAngles(playerMove* const pm); -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) ; -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp deleted file mode 100644 index 49e12064e..000000000 --- a/libs/openengine/bullet/trace.cpp +++ /dev/null @@ -1,188 +0,0 @@ - -#include "trace.h" - - - -#include - - - - - - - -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object -{ - - //if (!traceobj) - // return; - - //if (!traceobj->incellptr) - // return; - - const Ogre::Vector3 rayDir = end - start; - - // Nudge starting point backwards - //const Position3D nudgestart = start + (rayDir * -0.1f); // by 10% (isn't that too much?) - //const Position3D nudgestart = start; - - NewPhysTraceResults out; - //std::cout << "Starting trace\n"; - Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); - Ogre::Vector3 endReplace = startReplace; - endReplace.y -= .25; - - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, rotation, 0.0f), isInterior, enginePass); - if(hasHit) - std::cout << "Has hit\n"; - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - - - //results->allsolid = out.startSolid; - - // If outside and underground, we're solid - /*if (isInterior) - { - const Ogre::Vector3 height = GetGroundPosition(start, CellCoords(traceCell->data->gridX, traceCell->data->gridY) ); - if (start.yPos - height.yPos < (-2.0f * BBHalfExtents.yPos) ) - { - results->allsolid = true; - } - else - results->allsolid = false; - }*/ - - // If inside and out of the tree, we're solid - //else - //{ - results->allsolid = out.startSolid; - //std::cout << "allsolid" << results->allsolid << "\n"; - //} - - if (!hasHit) - { - results->endpos = end; - results->planenormal = Ogre::Vector3(0.0f, 1.0f, 0.0f); - results->entityNum = ENTITYNUM_NONE; - results->fraction = 1.0f; - } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = rayDir * results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; - /*bprintf("Start: (%f, %f, %f) End: (%f, %f, %f) TraceDir: (%f, %f, %f) HitNormal: (%f, %f, %f) Fraction: %f Hitpos: (%f, %f, %f) CompensatedHitpos: (%f, %f, %f)\n", - start.xPos, start.yPos, start.zPos, - end.xPos, end.yPos, end.zPos, - rayDir.xPos, rayDir.yPos, rayDir.zPos, - results->planenormal.xPos, results->planenormal.yPos, results->planenormal.zPos, results->fraction, - out.endPos.xPos, out.endPos.yPos, out.endPos.zPos, - results->endpos.xPos, results->endpos.yPos, results->endpos.zPos);*/ - } -} - - - -template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) -{ - //if (!traceobj->incellptr) - // return false; - //if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex()) - // std::cout << "It's convex\n"; - - - - const btVector3 btstart(start.x, start.y, start.z); - const btVector3 btend(end.x, end.y, end.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); - - const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); - const btTransform from(btrot, btstart); - const btTransform to(btrot, btend); - float x = from.getOrigin().getX(); - float y = from.getOrigin().getY(); - float z = from.getOrigin().getZ(); - float x2 = to.getOrigin().getX(); - float y2 = to.getOrigin().getY(); - float z2 = to.getOrigin().getZ(); - - std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; - std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; - //std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n"; - - - btCollisionWorld::ClosestConvexResultCallback - newTraceCallback(btstart, btend); - - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - - - enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - //newTraceCallback. - - - //std::cout << "NUM: " << enginePass->dynamicsWorld->getNumCollisionObjects() << "\n"; - - // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; - - Ogre::Vector3& outhitnormal = out->hitNormal; - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - - outhitnormal.x = tracehitnormal.x(); - outhitnormal.y = tracehitnormal.y(); - outhitnormal.z = tracehitnormal.z(); - - Ogre::Vector3& outhitpos = out->endPos; - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - - outhitpos.x = tracehitpos.x(); - outhitpos.y = tracehitpos.y(); - outhitpos.z= tracehitpos.z(); - - // StartSolid test: - { - out->startSolid = false; - //btCollisionObject collision; - //collision.setCollisionShape(const_cast(&newshape) ); - - //CustomContactCallback crb; - - //world.world->contactTest(&collision, crb); - //out->startSolid = crb.hit; - - // If outside and underground, we're solid - if (!isInterior) //Check if we are interior - { - } - - // If inside and out of the tree, we're solid - else - { - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - //std::cout << "AABBMIN" << aabbMin.getX() <<"," <startSolid = false; - } - } - } - - const bool hasHit = newTraceCallback.hasHit(); - - if(hasHit) - std::cout << "HIT\n"; - - - return hasHit; -} From fd45208196f824bf3536b24d25d8386e7cba302d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 14:23:23 +0200 Subject: [PATCH 014/185] re-added code for reflection & refraction rendering --- apps/openmw/mwrender/water.cpp | 68 +++++++++++++++++++++++++++++----- apps/openmw/mwrender/water.hpp | 9 ++++- files/settings-default.cfg | 8 ++++ 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cbf9c5b29..c19a487ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,4 +1,7 @@ #include "water.hpp" +#include + +using namespace Ogre; namespace MWRender { @@ -9,17 +12,17 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : { try { - Ogre::CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1); - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); + CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1); + CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); } catch(...) {} mTop = cell->water; mIsUnderwater = false; - mWaterPlane = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0); + mWaterPlane = Plane(Vector3::UNIT_Y, 0); - Ogre::MeshManager::getSingleton().createPlane("water", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Ogre::Vector3::UNIT_Z); + MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Vector3::UNIT_Z); mWater = mSceneManager->createEntity("water"); @@ -33,18 +36,41 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); } mWaterNode->attachObject(mWater); + + // Create rendertargets for reflection and refraction + int rttsize = Settings::Manager::getInt("rtt size", "Water"); + for (unsigned int i = 0; i < 2; ++i) + { + if (i==0 && !Settings::Manager::getBool("reflection", "Water")) continue; + if (i==1 && !Settings::Manager::getBool("refraction", "Water")) continue; + + TexturePtr tex = TextureManager::getSingleton().createManual(i == 0 ? "WaterReflection" : "WaterRefraction", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); + + RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + Viewport* vp = rtt->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); + vp->setShadowsEnabled(false); + //vp->setVisibilityMask( ... ); + rtt->addListener(this); + rtt->setActive(true); + + if (i == 0) mReflectionTarget = rtt; + else mRefractionTarget = rtt; + } } Water::~Water() { - Ogre::MeshManager::getSingleton().remove("water"); + MeshManager::getSingleton().remove("water"); mWaterNode->detachObject(mWater); mSceneManager->destroyEntity(mWater); mSceneManager->destroySceneNode(mWaterNode); - Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); + CompositorManager::getSingleton().removeCompositorChain(mViewport); } void Water::changeCell(const ESM::Cell* cell) @@ -73,7 +99,7 @@ void Water::checkUnderwater(float y) if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { try { - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); + CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); } catch(...) {} mIsUnderwater = false; } @@ -81,15 +107,37 @@ void Water::checkUnderwater(float y) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { try { - Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); + CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); } catch(...) {} mIsUnderwater = true; } } -Ogre::Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +{ + return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); +} + +void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { - return Ogre::Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); + mWater->setVisible(false); + + if (evt.source == mReflectionTarget) + { + mCamera->enableCustomNearClipPlane(mWaterPlane); + mCamera->enableReflection(Plane(Vector3::UNIT_Y, mWaterNode->_getDerivedPosition().y)); + } +} + +void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) +{ + mWater->setVisible(true); + + if (evt.source == mReflectionTarget) + { + mCamera->disableReflection(); + mCamera->disableCustomNearClipPlane(); + } } } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 5a5d1cca0..6f3c4a6c3 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -7,7 +7,7 @@ namespace MWRender { /// Water rendering - class Water : Ogre::RenderTargetListener, Ogre::Camera::Listener + class Water : Ogre::RenderTargetListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; @@ -23,6 +23,13 @@ namespace MWRender { Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); + protected: + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + Ogre::RenderTarget* mReflectionTarget; + Ogre::RenderTarget* mRefractionTarget; + public: Water (Ogre::Camera *camera, const ESM::Cell* cell); ~Water(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6372a31c1..ec105c8f3 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -41,3 +41,11 @@ fog end factor = 1.0 # Max. number of lights that affect the terrain. Setting to 1 will only reflect sunlight num lights = 8 + +[Water] + +reflection = false + +refraction = false + +rtt size = 256 From 8aea311797d2a441a4d3156e2b53a42c03e6fc68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 15:13:47 +0200 Subject: [PATCH 015/185] added visibility flags for everything --- apps/openmw/mwrender/creatureanimation.cpp | 2 + apps/openmw/mwrender/localmap.cpp | 3 +- apps/openmw/mwrender/npcanimation.cpp | 2 + apps/openmw/mwrender/objects.cpp | 6 ++- apps/openmw/mwrender/renderconst.hpp | 44 ++++++++++++++++++++++ apps/openmw/mwrender/renderingmanager.cpp | 6 +-- apps/openmw/mwrender/sky.cpp | 6 ++- apps/openmw/mwrender/terrain.cpp | 2 + apps/openmw/mwrender/water.cpp | 33 +++++++++++++--- apps/openmw/mwrender/water.hpp | 9 +++++ files/settings-default.cfg | 13 +++++++ 11 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 apps/openmw/mwrender/renderconst.hpp diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 4de6453aa..4c2ce8399 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,4 +1,5 @@ #include "creatureanimation.hpp" +#include "renderconst.hpp" #include "../mwworld/world.hpp" @@ -20,6 +21,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme std::string meshNumbered = mesh + getUniqueID(mesh) + ">|"; NifOgre::NIFLoader::load(meshNumbered); base = mRend.getScene()->createEntity(meshNumbered); + base->setVisibilityFlags(RV_Actors); std::string meshZero = mesh + "0000>|"; if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){ diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e88557f20..cf9cfab4c 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -4,6 +4,7 @@ #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwgui/window_manager.hpp" +#include "renderconst.hpp" #include #include @@ -211,7 +212,7 @@ void LocalMap::render(const float x, const float y, vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); - //vp->setVisibilityMask( ... ); + vp->setVisibilityMask(RV_Map); rtt->update(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c6fe023d6..3a4d9300d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,5 +1,6 @@ #include "npcanimation.hpp" #include "../mwworld/world.hpp" +#include "renderconst.hpp" using namespace Ogre; @@ -65,6 +66,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O NifOgre::NIFLoader::load(smodel); base = mRend.getScene()->createEntity(smodel); + base->setVisibilityFlags(RV_Actors); base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones //stay in the same place when we skipanim, or open a gui window diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 39ab0b089..bd39e1f5a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -4,6 +4,7 @@ #include #include +#include "renderconst.hpp" using namespace MWRender; @@ -116,7 +117,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) { insert->attachObject(ent); - ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); /// \todo config value + ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } else { @@ -158,6 +160,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); + mRenderer.getScene()->destroyEntity(ent); } } diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp new file mode 100644 index 000000000..5e1c6c7bb --- /dev/null +++ b/apps/openmw/mwrender/renderconst.hpp @@ -0,0 +1,44 @@ +#ifndef GAME_RENDER_CONST_H +#define GAME_RENDER_CONST_H + +#include + +namespace MWRender +{ + +// Render queue groups +/// \todo + +// Visibility flags +enum VisibilityFlags +{ + // Terrain + RV_Terrain = 1, + + // Statics (e.g. trees, houses) + RV_Statics = 2, + + // Small statics + RV_StaticsSmall = 4, + + // Water + RV_Water = 8, + + // Actors (player, npcs, creatures) + RV_Actors = 16, + + // Misc objects (containers, dynamic objects) + RV_Misc = 32, + + RV_Sky = 64, + + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, + + /// \todo markers (normally hidden) + + RV_All = 255 +}; + +} + +#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5dc41dc4b..608ae441b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -112,8 +112,7 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) void RenderingManager::removeWater () { if(mWater){ - delete mWater; - mWater = 0; + mWater->setActive(false); } } @@ -188,8 +187,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ mWater = new MWRender::Water(mRendering.getCamera(), store->cell); else mWater->changeCell(store->cell); - //else - + mWater->setActive(true); } else removeWater(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 781f7abd5..8e774eb08 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -12,7 +12,7 @@ #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" -#include "occlusionquery.hpp" +#include "renderconst.hpp" using namespace MWRender; using namespace Ogre; @@ -92,6 +92,7 @@ void BillboardObject::init(const String& textureName, mBBSet->setRenderQueueGroup(RENDER_QUEUE_MAIN+2); mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON); mBBSet->setCommonDirection( -position.normalisedCopy() ); + mBBSet->setVisibilityFlags(RV_Sky); mNode = rootNode->createChildSceneNode(); mNode->setPosition(finalPosition); mNode->attachObject(mBBSet); @@ -376,6 +377,7 @@ void SkyManager::create() 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); + night1_ent->setVisibilityFlags(RV_Sky); mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight->attachObject(night1_ent); @@ -449,6 +451,7 @@ void SkyManager::create() ModVertexAlpha(atmosphere_ent, 0); atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY); + atmosphere_ent->setVisibilityFlags(RV_Sky); mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay->attachObject(atmosphere_ent); mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); @@ -485,6 +488,7 @@ void SkyManager::create() // Clouds NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif"); + clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5); SceneNode* clouds_node = mRootNode->createChildSceneNode(); clouds_node->attachObject(clouds_ent); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 887721565..6c11f7485 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -6,6 +6,7 @@ #include "terrainmaterial.hpp" #include "terrain.hpp" +#include "renderconst.hpp" using namespace Ogre; @@ -159,6 +160,7 @@ namespace MWRender x * numTextures, y * numTextures, numTextures, indexes); + terrain->setVisibilityFlags(RV_Terrain); if ( land && land->landData->usingColours ) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c19a487ab..0ef914210 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -8,7 +8,8 @@ namespace MWRender Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), - mIsUnderwater(false) + mIsUnderwater(false), mReflectDistance(0), mVisibilityFlags(0), mOldCameraFarClip(0), + mReflectionTarget(0), mRefractionTarget(0), mActive(1) { try { @@ -25,9 +26,16 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Vector3::UNIT_Z); mWater = mSceneManager->createEntity("water"); - + mWater->setVisibilityFlags(RV_Water); mWater->setMaterialName("Examples/Water0"); + mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") + + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") + + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") + + RV_Misc * Settings::Manager::getBool("reflect misc", "Water"); + mReflectDistance = Settings::Manager::getInt("reflect distance", "Water"); + mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); mWaterNode->setPosition(0, mTop, 0); @@ -43,7 +51,7 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : { if (i==0 && !Settings::Manager::getBool("reflection", "Water")) continue; if (i==1 && !Settings::Manager::getBool("refraction", "Water")) continue; - + TexturePtr tex = TextureManager::getSingleton().createManual(i == 0 ? "WaterReflection" : "WaterRefraction", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); @@ -52,7 +60,7 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); - //vp->setVisibilityMask( ... ); + vp->setVisibilityMask( (i == 0) ? mVisibilityFlags : RV_All); rtt->addListener(this); rtt->setActive(true); @@ -61,6 +69,13 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : } } +void Water::setActive(bool active) +{ + mActive = active; + if (mReflectionTarget) mReflectionTarget->setActive(active); + if (mRefractionTarget) mRefractionTarget->setActive(active); + mWater->setVisible(active); +} Water::~Water() { @@ -91,11 +106,13 @@ void Water::setHeight(const float height) void Water::toggle() { - mWater->setVisible(!mWater->getVisible()); + if (mActive) + mWater->setVisible(!mWater->getVisible()); } void Water::checkUnderwater(float y) { + if (!mActive) return; if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { try { @@ -122,6 +139,10 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { mWater->setVisible(false); + mOldCameraFarClip = mCamera->getFarClipDistance(); + if (mReflectDistance != 0) + mCamera->setFarClipDistance(mReflectDistance); + if (evt.source == mReflectionTarget) { mCamera->enableCustomNearClipPlane(mWaterPlane); @@ -133,6 +154,8 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mWater->setVisible(true); + mCamera->setFarClipDistance(mOldCameraFarClip); + if (evt.source == mReflectionTarget) { mCamera->disableReflection(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6f3c4a6c3..44f765a94 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -4,6 +4,8 @@ #include #include +#include "renderconst.hpp" + namespace MWRender { /// Water rendering @@ -19,6 +21,7 @@ namespace MWRender { Ogre::Entity *mWater; bool mIsUnderwater; + bool mActive; int mTop; Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); @@ -30,10 +33,16 @@ namespace MWRender { Ogre::RenderTarget* mReflectionTarget; Ogre::RenderTarget* mRefractionTarget; + int mVisibilityFlags; + int mReflectDistance; + int mOldCameraFarClip; + public: Water (Ogre::Camera *camera, const ESM::Cell* cell); ~Water(); + void setActive(bool active); + void toggle(); void checkUnderwater(float y); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ec105c8f3..d9c908883 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -49,3 +49,16 @@ reflection = false refraction = false rtt size = 256 + +# 0 unlimited +reflect distance = 0 + +reflect terrain = true + +reflect statics = true + +reflect small statics = false + +reflect actors = true + +reflect misc = false From b3a186e7290663a258ca1def65584ac9a5edfde8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 16:37:54 +0200 Subject: [PATCH 016/185] simple water without shaders that uses original MW textures --- apps/openmw/mwrender/localmap.cpp | 1 + apps/openmw/mwrender/water.cpp | 30 +++++- apps/openmw/mwrender/water.hpp | 2 + files/CMakeLists.txt | 4 +- files/water/Example_Fresnel.cg | 116 ---------------------- files/water/Example_FresnelPS.asm | 72 -------------- files/water/Examples-Water.material | 149 ---------------------------- files/water/Water02.jpg | Bin 185893 -> 232475 bytes files/water/water.material | 62 ++++++++++++ 9 files changed, 95 insertions(+), 341 deletions(-) delete mode 100644 files/water/Example_Fresnel.cg delete mode 100644 files/water/Example_FresnelPS.asm delete mode 100644 files/water/Examples-Water.material create mode 100644 files/water/water.material diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 40ac9b6cd..cb3c0a204 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -225,6 +225,7 @@ void LocalMap::render(const float x, const float y, vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setVisibilityMask(RV_Map); + vp->setMaterialScheme("Map"); rtt->update(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0ef914210..f1d8d7550 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -27,7 +27,8 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); - mWater->setMaterialName("Examples/Water0"); + + mWater->setMaterial(createMaterial()); mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") @@ -163,4 +164,31 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) } } +Ogre::MaterialPtr Water::createMaterial() +{ + MaterialPtr mat = MaterialManager::getSingleton().create("Water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + mat->removeAllTechniques(); + + // fallback technique without shaders + // also used for minimap (because it can't have reflecting water) + Technique* old = mat->createTechnique(); + old->setSchemeName("Map"); + Pass* oldpass = old->createPass(); + oldpass->setSceneBlending(SBT_TRANSPARENT_ALPHA); + oldpass->setDepthWriteEnabled(false); + oldpass->setDiffuse(0,0,0,1); + oldpass->setSelfIllumination(0.6, 0.7, 1.0); + oldpass->setAmbient(0,0,0); + TextureUnitState* oldtus = oldpass->createTextureUnitState(); + std::string textureNames[32]; + for (int i=0; i<32; ++i) + { + textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; + } + oldtus->setAnimatedTextureName(textureNames, 32, 2); + oldtus->setTextureScale(0.1, 0.1); + oldtus->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.7); + return mat; +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 44f765a94..c4d2189ff 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,6 +30,8 @@ namespace MWRender { void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + Ogre::MaterialPtr createMaterial(); + Ogre::RenderTarget* mReflectionTarget; Ogre::RenderTarget* mRefractionTarget; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 203b40681..70458a14a 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,13 +1,11 @@ project(resources) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_Fresnel.cg "${OpenMW_BINARY_DIR}/resources/water/Example_Fresnel.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_FresnelPS.asm "${OpenMW_BINARY_DIR}/resources/water/Example_FresnelPS.asm" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassFP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassFP.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassVP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassVP.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Water02.jpg "${OpenMW_BINARY_DIR}/resources/water/Water02.jpg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/waves2.dds "${OpenMW_BINARY_DIR}/resources/water/waves2.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Examples-Water.material "${OpenMW_BINARY_DIR}/resources/water/Examples-Water.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal1.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal1.tga" COPYONLY) diff --git a/files/water/Example_Fresnel.cg b/files/water/Example_Fresnel.cg deleted file mode 100644 index e091fc587..000000000 --- a/files/water/Example_Fresnel.cg +++ /dev/null @@ -1,116 +0,0 @@ -// Vertex program for fresnel reflections / refractions -void main_vp( - float4 pos : POSITION, - float4 normal : NORMAL, - float2 tex : TEXCOORD0, - - out float4 oPos : POSITION, - out float3 noiseCoord : TEXCOORD0, - out float4 projectionCoord : TEXCOORD1, - out float3 oEyeDir : TEXCOORD2, - out float3 oNormal : TEXCOORD3, - - uniform float4x4 worldViewProjMatrix, - uniform float3 eyePosition, // object space - uniform float timeVal, - uniform float scale, // the amount to scale the noise texture by - uniform float scroll, // the amount by which to scroll the noise - uniform float noise // the noise perturb as a factor of the time - ) -{ - oPos = mul(worldViewProjMatrix, pos); - // Projective texture coordinates, adjust for mapping - float4x4 scalemat = float4x4(0.5, 0, 0, 0.5, - 0,-0.5, 0, 0.5, - 0, 0, 0.5, 0.5, - 0, 0, 0, 1); - projectionCoord = mul(scalemat, oPos); - // Noise map coords - noiseCoord.xy = (tex + (timeVal * scroll)) * scale; - noiseCoord.z = noise * timeVal; - - oEyeDir = normalize(pos.xyz - eyePosition); - oNormal = normal.rgb; - -} - -// Fragment program for distorting a texture using a 3D noise texture -void main_fp( - float3 noiseCoord : TEXCOORD0, - float4 projectionCoord : TEXCOORD1, - float3 eyeDir : TEXCOORD2, - float3 normal : TEXCOORD3, - - out float4 col : COLOR, - - uniform float4 tintColour, - uniform float noiseScale, - uniform float fresnelBias, - uniform float fresnelScale, - uniform float fresnelPower, - uniform sampler2D waterTex : register(s0), - uniform sampler2D noiseMap : register(s1), - uniform sampler2D reflectMap : register(s2), - uniform sampler2D refractMap : register(s3) - ) -{ - // Do the tex projection manually so we can distort _after_ - float2 final = projectionCoord.xy / projectionCoord.w; - - // Noise - float3 noiseNormal = (tex2D(noiseMap, (noiseCoord.xy / 5)).rgb - 0.5).rbg * noiseScale; - final += noiseNormal.xz; - - // Fresnel - //normal = normalize(normal + noiseNormal.xz); - float fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower); - - // Reflection / refraction - float4 reflectionColour = tex2D(reflectMap, final); - float4 refractionColour = tex2D(refractMap, final) + tintColour; - - // Final colour - col = lerp(refractionColour, reflectionColour, fresnel) * tex2D(waterTex, noiseNormal) / 3 ; - - -} - - -// Old version to match ATI PS 1.3 implementation -void main_vp_old( - float4 pos : POSITION, - float4 normal : NORMAL, - float2 tex : TEXCOORD0, - - out float4 oPos : POSITION, - out float fresnel : COLOR, - out float3 noiseCoord : TEXCOORD0, - out float4 projectionCoord : TEXCOORD1, - - uniform float4x4 worldViewProjMatrix, - uniform float3 eyePosition, // object space - uniform float fresnelBias, - uniform float fresnelScale, - uniform float fresnelPower, - uniform float timeVal, - uniform float scale, // the amount to scale the noise texture by - uniform float scroll, // the amount by which to scroll the noise - uniform float noise // the noise perturb as a factor of the time - ) -{ - oPos = mul(worldViewProjMatrix, pos); - // Projective texture coordinates, adjust for mapping - float4x4 scalemat = float4x4(0.5, 0, 0, 0.5, - 0,-0.5, 0, 0.5, - 0, 0, 0.5, 0.5, - 0, 0, 0, 1); - projectionCoord = mul(scalemat, oPos); - // Noise map coords - noiseCoord.xy = (tex + (timeVal * scroll)) * scale; - noiseCoord.z = noise * timeVal; - - // calc fresnel factor (reflection coefficient) - float3 eyeDir = normalize(pos.xyz - eyePosition); - fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower); - -} diff --git a/files/water/Example_FresnelPS.asm b/files/water/Example_FresnelPS.asm deleted file mode 100644 index 2de078ef5..000000000 --- a/files/water/Example_FresnelPS.asm +++ /dev/null @@ -1,72 +0,0 @@ -ps.1.4 - // conversion from Cg generated ARB_fragment_program to ps.1.4 by NFZ - // command line args: -profile arbfp1 -entry main_fp - // program main_fp - // c0 : distortionRange - // c1 : tintColour - // testure 0 : noiseMap - // texture 1 : reflectMap - // texture 2 : refractMap - // v0.x : fresnel - // t0.xyz : noiseCoord - // t1.xyw : projectionCoord - -def c2, 2, 1, 0, 0 - - // Cg: distort.x = tex3D(noiseMap, noiseCoord).x; - // arbfp1: TEX R0.x, fragment.texcoord[0], texture[0], 3D; - // sample noise map using noiseCoord in TEX unit 0 - -texld r0, t0.xyz - - // get projected texture coordinates from TEX coord 1 - // will be used in phase 2 - -texcrd r1.xy, t1_dw.xyw -mov r1.z, c2.y - - // Cg: distort.y = tex3D(noiseMap, noiseCoord + yoffset).x; - // arbfp1: ADD R1.xyz, fragment.texcoord[0], c1; - // arbfp1: TEX R1.x, R1, texture[0], 3D; - // arbfp1: MOV R0.y, R1.x; - - // Cg: distort = (distort * 2 - 1) * distortionRange; - // arbfp1: MAD R0.xy, R0, c0.x, -c0.y; - // arbfp1: MUL R0.xy, R0, u0.x; - // (distort * 2 - 1) same as 2*(distort -.5) so use _bx2 - - - // Cg: final = projectionCoord.xy / projectionCoord.w; - // Cg: final += distort; - // arbfp1: RCP R0.w, fragment.texcoord[1].w; - // arbfp1: MAD R0.xy, fragment.texcoord[1], R0.w, R0; - // final = (distort * projectionCoord.w) + projectionCoord.xy - // for ps.1.4 have to re-arrange things a bit to perturb projected texture coordinates - -mad r0.xyz, r0_bx2, c0.x, r1 - -phase - - // do dependant texture reads - // Cg: reflectionColour = tex2D(reflectMap, final); - // arbfp1: TEX R0, R0, texture[1], 2D; - // sampe reflectMap using dependant read : texunit 1 - -texld r1, r0.xyz - - // Cg: refractionColour = tex2D(refractMap, final) + tintColour; - // arbfp1: TEX R1, R0, texture[2], 2D; - // sample refractMap : texunit 2 - -texld r2, r0.xyz - - // adding tintColour that is in global c1 - // arbfp1: ADD R1, R1, u1; - -add r2, r2, c1 - - // Cg: col = lerp(refractionColour, reflectionColour, fresnel); - // arbfp1: ADD R0, R0, -R1; - // arbfp1: MAD result.color, fragment.color.primary.x, R0, R1; - -lrp r0, v0.x, r1, r2 diff --git a/files/water/Examples-Water.material b/files/water/Examples-Water.material deleted file mode 100644 index 2b46d6e08..000000000 --- a/files/water/Examples-Water.material +++ /dev/null @@ -1,149 +0,0 @@ - -vertex_program Water/GlassVP cg -{ - source GlassVP.cg - entry_point glass_vp - profiles vs_1_1 arbvp1 - - default_params - { - param_named_auto worldViewProj worldviewproj_matrix - } -} - - -fragment_program Water/GlassFP cg -{ - source GlassFP.cg - entry_point main_ps - profiles ps_2_0 arbfp1 -} - -material Water/Compositor -{ - technique - { - pass - { - depth_check off - vertex_program_ref Water/GlassVP - { - param_named_auto timeVal time 0.25 - param_named scale float 0.1 - } - - fragment_program_ref Water/GlassFP - { - param_named tintColour float4 0 0.35 0.35 1 - } - - texture_unit RT - { - tex_coord_set 0 - tex_address_mode clamp - filtering linear linear linear - } - - texture_unit - { - texture WaterNormal1.tga 2d - tex_coord_set 1 - //tex_address_mode clamp - filtering linear linear linear - } - texture_unit - { - texture caustic_0.png 2d - tex_coord_set 2 - //tex_address_mode clamp - filtering linear linear linear - } - } - } -} -vertex_program Water/RefractReflectVP cg -{ - source Example_Fresnel.cg - entry_point main_vp - profiles vs_1_1 arbvp1 -} -vertex_program Water/RefractReflectVPold cg -{ - source Example_Fresnel.cg - entry_point main_vp_old - profiles vs_1_1 arbvp1 -} - -fragment_program Water/RefractReflectFP cg -{ - source Example_Fresnel.cg - entry_point main_fp - // sorry, ps_1_1 and fp20 can't do this - profiles ps_2_0 arbfp1 -} - -fragment_program Water/RefractReflectPS asm -{ - source Example_FresnelPS.asm - // sorry, only for ps_1_4 :) - syntax ps_1_4 - -} -material Examples/Water0 -{ - - technique - { - pass - { - // - - depth_write off - vertex_program_ref Water/RefractReflectVP - { - param_named_auto worldViewProjMatrix worldviewproj_matrix - param_named_auto eyePosition camera_position_object_space - param_named_auto timeVal time 0.15 - param_named scroll float 1 - param_named scale float 1 - param_named noise float 1 - // scroll and noisePos will need updating per frame - } - fragment_program_ref Water/RefractReflectFP - { - param_named fresnelBias float -0.1 - param_named fresnelScale float 0.8 - param_named fresnelPower float 20 - param_named tintColour float4 1 1 1 1 - param_named noiseScale float 0.05 - } - // Water - scene_blend alpha_blend - texture_unit - { - - // Water texture - texture Water02.jpg - // min / mag filtering, no mip - filtering linear linear none - alpha_op_ex source1 src_manual src_current 0.9 - - } - // Noise - texture_unit - { - alpha_op_ex source1 src_manual src_current 0.9 - // Perlin noise volume - texture waves2.dds - // min / mag filtering, no mip - filtering linear linear none - } - - - } - - - } - -} - diff --git a/files/water/Water02.jpg b/files/water/Water02.jpg index 3efda7b6a88488f34f83ef292e57466db09818d3..b91430244629dbfbfbc5a027e198b1b3061dd0ed 100644 GIT binary patch literal 232475 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 &=wPF&?9=M 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

eA|Fn8kM^sm2AW1PW3TzCk^ZCP~ZD`MkB3 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 P5??NQhD?6@?=Sxk>yAs_ literal 185893 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 diff --git a/files/water/water.material b/files/water/water.material new file mode 100644 index 000000000..fd2589ddb --- /dev/null +++ b/files/water/water.material @@ -0,0 +1,62 @@ +vertex_program Water/GlassVP cg +{ + source GlassVP.cg + entry_point glass_vp + profiles vs_1_1 arbvp1 + + default_params + { + param_named_auto worldViewProj worldviewproj_matrix + } +} + + +fragment_program Water/GlassFP cg +{ + source GlassFP.cg + entry_point main_ps + profiles ps_2_0 arbfp1 +} + +material Water/Compositor +{ + technique + { + pass + { + depth_check off + vertex_program_ref Water/GlassVP + { + param_named_auto timeVal time 0.25 + param_named scale float 0.1 + } + + fragment_program_ref Water/GlassFP + { + param_named tintColour float4 0 0.35 0.35 1 + } + + texture_unit RT + { + tex_coord_set 0 + tex_address_mode clamp + filtering linear linear linear + } + + texture_unit + { + texture WaterNormal1.tga 2d + tex_coord_set 1 + //tex_address_mode clamp + filtering linear linear linear + } + texture_unit + { + texture caustic_0.png 2d + tex_coord_set 2 + //tex_address_mode clamp + filtering linear linear linear + } + } + } +} From 052cc47ee92488dfa4c233ae5c30414e3ef0f00e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 16:53:33 +0200 Subject: [PATCH 017/185] fixed waterAdded --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwworld/scene.cpp | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 608ae441b..ff4e6786c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -128,6 +128,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) mDebugging->cellAdded(store); if (store->cell->isExterior()) mTerrainManager->cellAdded(store); + waterAdded(store); } void RenderingManager::addObject (const MWWorld::Ptr& ptr){ diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index df7d20bb6..2123b4799 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -204,7 +204,6 @@ namespace MWWorld mWorld->adjustSky(); mCellChanged = true; - mRendering.waterAdded(mCurrentCell); } //We need the ogre renderer and a scene node. @@ -257,8 +256,6 @@ namespace MWWorld mWorld->adjustSky(); mCellChanged = true; - - mRendering.waterAdded(cell); } void Scene::changeToExteriorCell (const ESM::Position& position) From 6481cf87fca7dc77cc014130f97b66bcd963533f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 17:07:16 +0200 Subject: [PATCH 018/185] cleanup resources --- apps/openmw/mwrender/water.cpp | 5 +++++ files/CMakeLists.txt | 4 +--- files/water/Water02.jpg | Bin 232475 -> 0 bytes files/water/WaterNormal1.tga | Bin 196652 -> 0 bytes files/water/WaterNormal2.tga | Bin 0 -> 196652 bytes files/water/water.material | 2 +- files/water/waves2.dds | Bin 262272 -> 0 bytes 7 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 files/water/Water02.jpg delete mode 100644 files/water/WaterNormal1.tga create mode 100644 files/water/WaterNormal2.tga delete mode 100644 files/water/waves2.dds diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f1d8d7550..a6479c401 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -169,6 +169,11 @@ Ogre::MaterialPtr Water::createMaterial() MaterialPtr mat = MaterialManager::getSingleton().create("Water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mat->removeAllTechniques(); + // shader technique + Technique* tech = mat->createTechnique(); + Pass* pass = tech->createPass(); + + // fallback technique without shaders // also used for minimap (because it can't have reflecting water) Technique* old = mat->createTechnique(); diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 70458a14a..0a38ff8b5 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -4,8 +4,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassFP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassFP.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassVP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassVP.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Water02.jpg "${OpenMW_BINARY_DIR}/resources/water/Water02.jpg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/waves2.dds "${OpenMW_BINARY_DIR}/resources/water/waves2.dds" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal1.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal1.tga" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal2.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal2.tga" COPYONLY) diff --git a/files/water/Water02.jpg b/files/water/Water02.jpg deleted file mode 100644 index b91430244629dbfbfbc5a027e198b1b3061dd0ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232475 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 &=wPF&?9=M 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

eA|Fn8kM^sm2AW1PW3TzCk^ZCP~ZD`MkB3 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 P5??NQhD?6@?=Sxk>yAs_ diff --git a/files/water/WaterNormal1.tga b/files/water/WaterNormal1.tga deleted file mode 100644 index a9ca11b7ed0a44ddbd9d1b5cd8d699ade928c4a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196652 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%0A>`i> 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 diff --git a/files/water/WaterNormal2.tga b/files/water/WaterNormal2.tga new file mode 100644 index 0000000000000000000000000000000000000000..771d15041922130687cc943d8350165c7edadc0e GIT binary patch literal 196652 zcmZs^PtRr7b>^qer^pA%paaAnSnUScZh({>kWvg(soRYz+Jh?g=yLeZct=syq{RY~ z77J)gB+@nsI86Z^Y2f6e1V|!N5(}jwMNu@B-|uu`Ii2_ytzl4 zH>Z1FZu`x{JHLH+?;jsL`07E1IGw*dJzhAHi>Te(2`^}>}ZU6ZAfnzz`7{_BA>x5KaJvjg4gU3gUb2ILZ%8saG(tdt>=yQ5b z|2mz2&vEGa9&c(fQ1P2bI-POr=y>GlEgc43<5pG14*I>i4!I; zzkmAt{WI^Mef0h3AARrnk8hs;_^lToKK%UYeUxI{FYcT^f9>?*m50B2^$p&C^*~c# zpD&)Czj%rTX#T6s0r`UyS{p2lf+GLH`OACf-`;!l#l0uLefR{p3Q-j?PGhlJSa%>c zE(ZL>;AijNees^{H%}ij79%1&P1g_z4tMj#otw{JJOBE%N58paW1v7T9iDHLGjSbA zTq7_xIX}R^bRHwvKe{xi0XgB1Bz!^-pTG0;vv=R+4f+;@qN1QuW*fqw8fwybj}h=V z7W?v^pQ|zyH}NHG5@>@T`;?^(mIktM1m56D3~S(Plkh;sWyG~@A*2A|XYd*Ho{<03 z^DEUt2wfO;#88+@9wtG&hFfjrpwi=UjMOb?f#112srNa6DERG@hsc&-nFz%TV4enY z2mu=JHPJzXg>jIe3Twu^iGK~ix+7>I1W?%?ZlwUNiteGWpfT?cdO@{d%nT)=oj3+Z zgMVNj{NM2U{Ks$q@+aT>`2YN$Kl$m~pZwGi`22lr4wlYe+&O>x%FU;*oWTE!*Y6V7 zGREWShu#3Bz<_B@YC!$OF&-u}-xT=;C$Bh{KBMml7N-N(2>~TM%lx0c^ZN52y!ztZ z*NMb0o}P;T-#m3J2ud%UJ8xf3a!bNMG{#f+FS7w1*47{Vfd-t>V?tl8> z>C+F-bdD~72VfwB>F<2UZ20t@7w^3b{&|xa2`dI0jl=*+gd-0z9!XHV;P*9B;bN(> zfT;n8KSQB>r5{rj&=qc79Et&;1^$6qFc|vViUW9sL4AlGOB|p_E{} z1^&c>v|s#d2d$xJZ2`|E1Y)QH($Q1EXfb3+3(S&|$V$?3hzrM+>o^6mK|26QMrcqB zY_KPc9SlE2{?G2-<&~mt=)FRo&j4)dMof3QLCvN=PCSs$n?iJ?l9875Hd=!a9sTP^ zul?%#ukw1-KcO1yG{&OAatSx1fTl;(H?TRKsM%B&Mm^tf3hX^05CCu_LpQ{TFS1PB z_lU!ctdzb7{y7pu0siMd`q5|aiT`9h4PFQ}1a#%;v9_|nJDdgbw?P`IUO;j|5@!u@ z85bI1-Ky(Nti)p+3duYqAqM{@wT81{Vip+oARGq3oPK^_{NCKb4nbXlD_|SR&7px` zaU!)EziUrSwBV0w)y@M3fs#PMgY|y>zO6K+K|CcMiFmlP*%B=79_Z{mEP37 zrXk}96@LBjHTy}Cv&?qJ??g&5sS{HL@h!Am{KL|KKam^coTspi-xHFEq#{GhARq4P z3~uXf?S{)L7-KnHW@?FL(W2!aHv}FKq=|QMWq5w}&U=GxW5iJ!Vq}>wp4?Nr^JDvj zKTl6Ei}lY<@N;udE1e%V3y?RHiHchp)t16I$SlmRkshDgw*Fd4UsJq5g5=Q&B{a3O9=e>QCBwbyS2fKN3YO`0_?^y==leTn0iJzOM!#97 z?R?vbQtXg^YME-M%oqIY2#p_0YSQ4%V`78`T^2Nwm{1=hfLQPhnHUHxsXcXqkU0XA zWdc0bv$X5n)7PEi4f{>(8(dAPNz<9Z6$!|rLytM&;)G8$V-^!cV3H=U#B4Yr)<|Lk z&+@qnUYNg$67{v}>49-NC7*;jr=0Q811Hz-ybk_}wSeUD=l7p}cK2PX_u)6DOQ{^l zbXVj#DMqtjbAINkLS^Jpq%^$`LZHW#SWXi8q-~DV^~aU9r+k=M5(Ab0 ztEsNk)B}DL$AApv!2mdfi7wc)$njtRpD8)mZo~D0-+ytsJ&3fEG&pfl9a9{FXIBVm zPw&^E>J@AwQo+w_El||y)5X7rO7Vl6ZX;j3`AJehBv%IL<@e%WFEq;}C`LgkW!6c+ zM$JxbmMI=EcD4ef8=j>ag%^Pt=w!jaq#YW>eeW|pq}`DHk4d6h$Qy~%F02jp>HWB7 z)U2a18l+LW2ml)UjEh@CmCjhFp-U~+T)@8<{AcwQsAn|>z^Jb+guv$v?da6cU6f9} z*BlCLI1EXkeejPwdhNto&7+ck2oQLfD0!s?{Jtq4+VdiR026P<7bs3#&pJ}G5|Q5W z0JG=Y0l!+OJQ&^0(W^)}vt|iAn&>rASxb~MXel(2h$9jL_(JGnwEDC|pyQY#%IdYG z__9-xUtKbsbSn5=!g}=iop*SpHC{a6vDp*rF>h*Ihsr9RTHt*^vWb#^4d=*{7$N!& z{9CGBLg08GO`~i>braCwE$ca`HjXxf%vy?G146N60xm~ z^-R})@KIV*Lki&5)i>6_*bPfkhXa@}_UMIb6vJH%sh1l^*de{mVdVj=5u1btnZcz1 z7}wthfHse6^_S&GS76E;p}sh1s=M}I@C(b}fj3dyykL~oR@U=QXRH}m0S^9K`6Pa4 z-YUtQM{x-=NvFcdU9AVGy)#E>&2w>?erLp6A;2fV9*_|A0g2#0U=L!0XBog|UPvHk zF7P#$_NoHL|dAVqOdBm$8Wa2nTv!Hy-5Rh@R5FrP)~1K!Fr9vSd|_WC>Ee~STA zjOMzr_#t(6>V#f%RwRrfhQO6~;s}}T7Nixvb7Un4!)9#_vZ#o0lJQSZe)CXTP7H>c zS^_-|&0eQ~R1Wlz4h0^*HqpQPdQ$+)`>gZOz<;K4lsDFy2#o8g5Lg4Dm0F2eG%X10 z{p!`|=Ja%BK($dFZ9B76LV)zhYZx57R0$*MqyX_B%9X@+`q>o>Y+moj%eRWm#Mk8$ z{_V7pSJc-XCB4kKQZfzx=~-{Oq?QTn&0G_-LjgILzz`Tv8MeW{x%f2GWL0PdE8(=Y zt`h)hQ~4iSuTQN&f`1^9APqbQ|8yH{gziB5U|V2V8wmc;^)M%A8UCqtt+h%r?J(s; zhXDWPva4%_U7FxE6Ev}1BQs)|AN=>2)VHw}vy79M6=)D6mZ?;$S9QU9;}N9tfP}_+ zuqr5gT1nt`2xNxRJ~4#`=X%+4veZN^w{%3{q@ToiX$q6B;vCsk6p$1+mynx*uD)34HEYKylC-ieNbu}uVg#bMLLe-d|N96R6? zxl2l%Dg1$dKeu?xC=dlD+{1gUSU!LAWd!C#98@n0&deV*U#Iuez^Ta z)-Z9KxoiPp!dA0m@YsAVPD%d2Pc%}T=Q4UQX^F*=9N!)SMF4OZt`gFpeRsJPmBNB zP)O*A_=43KQ!SMgh zYdOU_Dq)q&j&r?Z48DOpuCMN88x;&u^i>ds$@Atq1ZKz1;QyFP?4^VqB5|>sJ@^oo zK;;Afguv&g*QBGYDs(Y~J{2Y~gJh2Rotty>085^1L-sg$TXL`BywTJXec>w=UJrkmn{Hw~`vYAzdHqQ0&- zQ)kMb(5@pCxD2U0qFM^-1%jK$pP$~R9rz#d0Q`nY!C$vl-*JKXmB$5dmz- zwo`!HAt1@)&;$RmSTG@nAZia`cMC96GFW(JR_@3reoSkK*Y;IcMS)HXc(<4+~4Jq@jQfb!N!_ zz(3)@Cm7sD2s8}GZt`THD}XUnW3W&OkKIl;sfa>Z6a$wl1=rn{^x~HUNXiDP1w#qK zR4IhNz)58hi7fW2S+h-G7hQ zOklB6NINMeeQx>Dnndg=XUieMkR<}W*=EVtNOvq$Fu*UDz#QFkotTd>l+fb;-MeHN zgh$z(Ajgt>RkW;9O~tuxTF+jHXvE96hDl&Q^^#{r{`q|8I63&*hIPH7A`&4$Amo%@ z7=pvy%*ky1`P(nK8w&hmlc*2!Tg}FpB1C&$O)DlJZFbN>VejG-$0Y=|zz#C?{zGT$ zW}lH?!!n|y*i}~QivOdB3m!c9a3!;VUjH%{vXhX_B;8lmD6qrsCTcirl%W^vnJ*rG z$SdQD%mS|%%YM9M?b)r@4Jt5LL5m$mHKW@dP~ByhYa-#X1%Cn4pr|n5hn~k!naCf8 ziiP!^z!-rC{|@IT4XCw1(yM_M4nZk2dU5wXixU?lFW0vA3dQzJS4aOd5pE|kgN!#R z%-~80gfz0uQZR6Ojc~|}gv3I@PZS^(IS5}nzqvla>$l3b%-P&wW$1h@;19i!0utJt!@30YC=>RXuvi^o#x_*I@5l^U z&5TCEpQb?~Vf;JfT-FLm6h7`2JTN4LK!*d%Mtv?}q{Bng<-H3M@cy>2Ygo%g7%CrN zPh$gKw-NT56m|~Mrq}?Y;Ir!$%-z5VRN3pfb5%P0?mEC z;sq9bD0`q&GeQtznK991yrhXt-iW2EtCn=z$fBz_Zf8kxN`wiJ3u)apbSof2W(5q#iI80JL@-W4+L=}xUxqfHkIWOH6=_RW z6Ac1Pbz~2L76@DpoJgO36kgTT4!;*giDkVo{@QP|Q=-W?J-drih`xTeg%CCj;Ke-1 z{PdOc^OxSH@#e)VkDkB!15^{7PU5CAp&xWdwu)Eq8}-JK{db$UiRSKIryByy{hT!R zS2G-OM?R7wbn# zWR|ith0ZNnS`ebzLaVIk0Uj1^2M_g5!=e6KE&?is7&0@8$0u;;5HHMh;Ld$e5&XOJ zU%Z!&K!Q;~)Yn;_{c{K&tn?73n=i)`=-_j!GLDl3iW#ITFIxNYE1Rb6#M1hLPft0v+FPBuZ zusrflDCJHipiT=0VuWl8GIG6r&pm$h+_Y63#*8FBQ9-b8@EV47ih{u&iDhEH_V4{% zj*_L<;C~j4LH@W{rJ|Rt9^p3yAPJ~w6kNR_E-Xs(t!X;yi~k7U3L(icIIP$3rZRgQ z)D*686i_dCu2AiAZ&7?H?$5Ub>SLjqEYu$n0UUBPQ(2%E}OUtym%_o)#GE>^s zLCv8isW4C2W3iEn*R#@(@-OoDO(;v^inIw>x-D-6W?2-vUvA~mf{m^<~@qfjQS1fvRl>1(t6ksmWX02N@#;xU(@pwv? z+xI-yVhCA;#Fd8)r$#OQaYr0lmJqQ)j!~w6vyxdCa2Q3JS5D9F0O?M%$wwGD^?5U$ z;78MlTGs<_JW}M)TVWjMf(l`&L!*w7Md>cQFLIVWN|n&m3OT$QlWxJEI2tQ`9si-4 z3|E)MiB=RMA>icmBh$rngBBec9Ez*nXCZN2($hM0KWQeq2qQ|C}|Z3$8FJhNbZ#Cc>dL zRHSNbib*=5Lna_JS7?)Pxz5|YNi0%jt7jH(*^dzv0aP0CUNB!ebX?iha7)pP3*uaK zi6RxXlPPPPsiP=7Xv{i+1U)l~Qn_3_nZ;-ghZr@3x0wB(fWJ16F*OU49QfBSwOGn3 zzN)C$8LQ$=3IlDM`xdbk9=|w(D7X-s7OR&%AhE{3HICRz+9i)b{?A{2lNBezE$B60 zgDdJHKIeu|EtzFroTY54gI-ll{D<2^8ue+>m2v{)_sI;pHRW*tBXX1>Rf^qWx2xF} zYn5^6joY+tl6p`%wN}A{gjmM;J91_%i!532^NJQFD7hlGs=@V_u`hJn&%8#X;sjk_ zR2LX6?DYko!~dNQr1qF{1=EEwgj3unR8Y#|Eh|Miy{UPx3nUQMbUF)p%A!@@&^w4? zBXp$2p1EqzrB4p#Nbvvs#-)A*=5`ggvSiga6A&S-BMvskYYrFtYpX&IL&0yn8Yvej zYTncy1AeLwz|ZtE_*ZdECuKPUGAE`XVcJmHZSY@LK_ySoVmqv-JDTj0UJ<@NMVQ2< z%L3p(s}Q+fW2n{(PN1+qtv*FfEPy*Qv6959FR(B0_?Gu*JzUEDo_Fq#P3|z)b`2K% zmtD1+6m7gCp)Em;1@ITXs88ci>2ANBI} zd!Sf|pauUTzxdDV#I->O*epRq7ekEwsW=R60nZ;0z>vNVYA=%o_ zKJ|jF4m2k06a%V|+vQ-4BLFw6rijY2QX?9T=oSFDe*XHqOcQ`K(Mv>4de{#)|Io&m`b1;W@ghf+2BQDhz=5IY;c$lnn$ zg1Y1iSHNFf>5&2e-bUc8XJ*Efn>14Zi# zaY3C$U~Ui0Qo~^@qS%VPEz|!1{=h%>G-QNR=TlvQ-#r-drqKcI=<$c%1dW|zc}Fa> zjUs?Qli#WLlFe~J4i-_CMyYAVc50H%v-nhs`x^e8)8$qOu!o75bUc6aBVLJ9?Is{+ z$>lOT@D9zfB;z7Ku#BO?_7^V*%OZ2YUm#5(cfmgbyZFQYF<0GX)N-lv%ZQJ3 z6qzWif7=$`x4gV5U_SI1W6j_T-eT zrC@C^PsPFLtN-y$+_oDs7a37VZ5PfrrmooqO%!&;P~0H3a_kpAiC> zTJL0gCpN)K*5rv|EVFa2!#cfgsP?v{*8_xT>PVB_}`+`);_z_EIZa@0P%AXvT%|TF|;< zYfOPuL0L zOK!=Du5zR_WvqUF;NLk;3Pp9#_G7F{nfmNI-va;CLKH$+o3joRVRPWYB}I%W+H=D@ zP$~XNG=hK0AucX0)PRc?05elvEF8GzhFQjnYzMG4Y4PLhf$IZ18VjKCs4SU&pg= z{qXs>e}tR(1S2QG9jVRQn?Q~Y%N3-6OboNH+mJ6IhiMCbf~76_A_v!5#`V^62^@L` zX2ITgA(0!;MnP0Kj5B`R3*u_prl&4-Q5?G1sKvlP?UL3x-r)d0A&?Q};Q|cx;eV%T z*(XoWBqmCIq5uK-@WtKNiGpAJ$^XQ{1uY8~7Hk-h3Li^8`_A7M|8R&jG9`Ur8KM@Y z(Jn+0SSsh#u~KwG03eB57EyP;jD-AKgKO&R5Ew5w%C@>D#%cZ8q!~?b;~#6}ti%!H zQWOPjS{3}0(THml3AHMfg6YB8wy}&?Ry3igV6r^N@SYA?W2E_&=_y-TZalp=STQdv zTpgElGgD(q#qC0wShZ(`tl|JHRx(|Bd`b(?MYh^@G95zB?HwjgSI)&6>Qp&PcQK(p2Th-WL{IQRDAZ3pNJTC#p#F|@VDnNyQer7w8m@tw6|5<85#J8 z;ek4neZR^RZq>Ro_dEAN{x81ym$ZNQ!@v6EkKS^h47&xEOn?gZL=4VV;H_o{neqTF z#8sE&-->4$Fe%k@nLZd?-LLmD&|=4*o+Uj)j_(J(eQ-#G3=p z;0Mgpdch@7S0p+?HU{E=V(egA12Bxrw@NbqE^h||akK=21+c1Q75q~IUE+Eu;wUgQ z6nu#NAx16MwABiylh)R>7&&ZE+45?D0RH2qA@ESGYm;%J-s!ChE!%{R_`ie+7S5W? z6`bO)i+|(0f^C9gyh%uAHPQeSEshmDY`JALB{dkHqc!;mmAx+W?Qgfv!E}WLdf7=h znRUxwe)G+b|KQ)#5&~~Od-?mAlth4eM+*lHAEqWrICK;-DIwT4k!5v`nlM5J{Mij| z5+McT?v+WGnObVVy4yq$WM0U>|6Z9${F{%`bSte@UyK>MNl?izsd(!?a-YvYX0g`? zVQE7d$(1fWuAK)n_8)eF;m3(v)zhb2twh3^>!fx9r}dF3?EWPLv})Tje?uTaA>U&E z!v&d>c4jKgB4?v@t+8D#jS#t1Za4)D7s*yW-~Q2yyYHp!(N;51EIDox5@Mc){W~iJ zz@k^(_bF0PXfCRv(a?2nE=vr0b7ifEWw2EZBE<#s0}_$2RLNoDyc5;q)dTW57S`AD zfSlPDBE2F#EP0K8Q$Q9~mKMex6hBkY7W_#lnxb`Jc5Th|Xo4}<%4==8$b7*v2(wVr6?I^d%xJml@un-B5h+Awu>IiC>?E0Lcd zMTqqyJz4$}`{_IX)-7;nL^*~5ew4Iojam|1q~7w#_jQ&jY#E%+bsry8-$ zF8+Njg?0fd3w`AJCgrX?!}-!w_gW;Pi7Dfqd-QCFKx%*~agCteQ!U|?KIa7ix-cOQUkQODX5=$-Za&UyI+ zzZ>I(06xtPjKTlxx*2_ijetoLcr?xe;eZqS2&%otjbO;2@$=}m_AK@^TFG{VFEfmN zs04;rlZN1d^{o7#nOB{QBrDZSP8+;LF76xrb9xLIgI_`~;n~G}bZI!0tjxA`A39QF zSZ1UX;LQz0;J>$i=q4k`$`h$Z$7JeCrC%l`S^NZGeVx2eeMk2~C=A2t2Hoz%M*t)V z+jPxVjhK4u&K5muk~(!&Q2vjPv${`G8@1-d4nNplZ-6PcG*oxVxY;2-1<{$*fS zpJoDLu#0>h-8Z-rWq?NqU+GiJv`&5cvs$R-VM>q8S!i^EL}%gh38GZwx3j^hJSE4y66rm2n_HrYMNlc)J!pQ$=gf+ zc^dW+n+d2OBq?chl-Nh+crE!o?gKw{sP5>{dE5v7f{I}wzukp5KwviRv#E5TxxXLja; zDY8Kwkf3!N-C{|UqCD8hGT61P<3=RB9}cJNq)C0*RDe7aXj`lJNs1-l4gU44Agq4{ zGZvec!@#FKmp~5CM&THguumdjR;@up^ErAjyBJRmo#ke9?d}BhX|IiEpr?SPOb$vHu)r)M$~p_ zS7wS*qE@m`DZ&=6=$lB@z)^ixUwL3P^v-+TlrWT4c$BNN4=Yu|5b!^L>&M`q_a3&i zfX$nHSFlYVUfp}h!_dfOgaBR9=TRiIbR?#<|LnD!ZxOQn*N-Y%~~{pZS!}G;?(#k9-dpm^!t& z6wp+TUI+f?eI!RD^$PiOWZNYeHw5%lkI#Hidf!#MQJ-jP+n_*qjDRTwMxr1phYzdc zo^s%y9zcj(baon>FvJM%89>L@bz(b}(v{iI-U9RL4_GH5e)$$h<3#kuXy&q9f^qaX z?#SIS_%gr}(PAl~-CI9yUSp;Mk|9!-A5)yqvt^FG5ZbUIAG0tJmQ0c98Z}11F9JX_ z&LW%dQ$?tVUtK0L{@g}>wjlA+S&XZT9;UO-K!TOtqg>H$O*HyTbD5w`z87j@lK%XI z@6z~59qJ$K8J2)XoH~7a{*VSwf{g}RX6{2rO;rvZs7yi+6|e823w)CKTJ@Fv=6XcH z9I~oN@yOI{m)__wJ{nKu%2)BP6G@l3)x9C0%Codv@4VJ8PW@0pdmXBJS*#?l%zlj(*A$&7h+Ys8g61&A~N18AIDUVA9kzuq*51H3AGj4C2 zQ_56HnjB!}Ld}9-%QUT*{StkN0`Xt1@eAkD2`3^doI@M@8v-?v77qSRuK`1|X8;@o z=JUzONX{sYml>$czjT*w$E}Qu*pc6CSOF?SbHOshkrs`hBOHoM^aZq7J~i77kKOQx zkn+IovU=R%KoIQp+Bljr529R=+?YhUs}kx;3_p|rcnvfDM%2nt|4Y?C1sGu>Ot*rSfDe$VSvJ8 zmmnZF6eqqgRHk)v1u$qd4WSX{LZkuAV;^N{<@2L&clyAfj-@>2DMK}zBuP3h&(^=P zeKt?#fle~Uptmt-a))4XXgkqpIYtr={t+Y24eC(S>>#S4scc7-pNADA3E%dB!#Kie zF0@%?1%90`gaGBn;HL?6t<-*Ec^ND%c#HhnoD&nU@pX{U4?{i&2VzfidhnlIb2Vj1 zw*@xpBQQRt8FwLyjB$M?JHh?o_&OC8?;ww`jhOY2&aqPp;(%RQ8V8!cIjHKyJcJ*w-$M-18v@39!BBV8I?`+HAhMuZIbYXO<6{U9)G!YXwgBLGi~}l2j;@V|H#Ao&5YDC5alyaEiQyB=bh!5K`+(Vhi~q29qG{GN!kOjs zjfLwZ(wW_YKb<3nk_3235G6Wa^|g*O#H^06DoE4mr2-w4&kd0DV89x@sDKR%{;IEF z4b{n3i6B0->2b`WWrBZz6u|IRycrIuTm7WJA8|a>_-cnLn5XQKN&3VgR5+jT`zQbL zU*ToOB5#6!r-!p{5Rb>FIz9Rt-C@fSBP);^Jn9!VPOSWmBv6!nkMzd$lbxAo6Ak=N zZPscbwvxk@oH&}ha>`mM-GS3SR6j1xZn}_U^A7H=C3&L}1b=32n%(Ry+Q&pvWgO>+ ze8sp}07)>yvmbs7s?XzFIgxKqlxnk&)Uv1jq{EUGpSW=67Km<~%RmmHB%w;o$k6^P zON*t%&SU|K!{c-C?*-8P@zat#2dmw~%dJ%aaYMnq*JqLp*`Uwu`1 zSk(76Vofj)rRUqL`p0j@?V7H})D9vuR1ePKfiMp?aSIByVipQ=!NnQJ9&bNVI;|a! zNLi^%p-!!CE58XLQIvruFgG_XX4bh1rgp7kv(SnGK|7e2?Rh*x?$BJExabPw;dipU zd4C_3SrE3^3lj8cIV$#as;J@(#)DBa)k1f`51djn>|M9OiReB*0Qt|q_c9?+{HvFR zocOQfgb=t@Yb}70k@l#d7!jg&v3irsH8$3sntG6*)QlpdOIXWq@pX${B0 zzsm{b|FA0u)Gu=k0xL5|F8-Tb#J|^$F&c|+xx(nr4&wbR1qcAIInHLnM#0tSF(cR; zGMp8v;y=hQ{x<|_y@HVU_z`7kC@ZQLr6!BaJpsQ(uTQR!6%Qe~w93!Z@B<&uK6=CY z_8p&biiNG8vzk%N6gIk5wp46r%1Sj?C=@1U5xPVEv+aSEfB2v6VO^GFT>3{xJ_rB2 zf`21!@Gtl)e~>8{jEjgwNrN{V+JK+n;?>l1^5$GtmdIr)7=n$*gKblrl_&UA41Rp1 zKUI0PC=v9!U$hyJB$%9a#sXwOBq{#)u0XSSo7MjKg%6$Op&5#A7v)u!T@5R_dct;<B|VT6s|1mT;s;xE+fnhK&777Nv?TqKtw99F zuspxc(BEiip>hBij>1zGKanaS`M4LzMBV8g{7-Wk3VFnBk>5Z#ifU)>F2035cwd{~ zmyO)aLv?YhD(3c45S6M052pgxW9I>_krHsT`T9^@CK6T9sjkF0~F8;$Lt|hMT zykgiwF|okExipg>0^lr1v=WeG1$lA4$QLJR4wSD{A(2}n_mvRn46&1}nI&<9bAQf> z->K)<>ixlb@Gt-8jy4sHK~xZF4cPbsKN?wsf2kwZbKgk$UxS;?hy2q?@PB&ca)m3K z;)o`3_(cAPX2BaU&bf>K%%CNf&bDF!6dVCk&*OJ`z&n@%O`Q?vo(0|nGqZG@N;M8m zu>@N(G?oYd&p-G9fxvxU{M!(y7YIhO5;1H1=8?JOe5Mo~AEBJ?ji@F0IA|!aQbG*|XJNX3-;b90k znF>dlwoo4rW>7;OBEs^0_8r(GQm{Yj;0s#E65+K>aX$5-+^Ye_YFl)Peq*`U)AGHtK8IXZB%e|ex2$y`;}u)Tu-`-I|(|I3WV z+%fwH3Ny?o_+=*uP0RBeCA9v|R1%#2;#=_FgoRJh8vf@M!4QM_FClu@IPdM#LLQIT=A_M`xXSDk)t3h-bo7XBCcd!#4}zVcH_;6L{iyT38u_cfTr9ZdvX{LxmCFoaY5hd_?c$J&AGbzln7 z#3pWKvN=CHm2!ep!Wima7A1jFKd=_TEALBOc+(@Nst^8^Eis-5rGHw2QA639ttdHi z-yiAQ1jHg9rpx6aX4&AMcr1r&)ugas-pxx0#wR+$;&$=x{JL4MW)W}Tgew%qSTrg> z)SJnkvWIV!lW4LKA~l-@xJ>L$iR{ykm-CZ_H}jBE#BevD!dU+l{0II^6iKq8y7D&? zNk;W}Un|>T>UCKnG>{{joJ_eA;)My$!sc24;9<$`S>?ABdoQz3>9@upY#X_uojl3P z*`>#$?BNcN2^;fy>{%c+`gB%VE5NQ6vGAH}0H0L?JyJKxgh#`t6E9d;e+8>K(J)7; zVu^DJ6Bwp5f~GL=e}#OD^QML-<;q-mboApjsG$E93Bv3;TR67HsZX&6fq6WCmBj=e zK*5FwHwJrGzG&w?W=GD{4}9q7zTbyb=nm8UhW6$-p%rx1;2co!qty5!>3fROq%9bX zHI_@|Z{@J7f?XjGZN}6Z6CG>AFs=2iy~&?W!GKB$Q}E-I-5QNkq^}h(esSrzA;4kG zZU8@<7Q9eybnACK=sIVf(oDD3|8658D`iJ$uVrWSOfkF~l|WEPY{eXe*6S&nH^2V~ zjnEi^ezZ@Bt8a>y=m<_mO%HCSlU}SAP^1J~*#d8Hz6cbJ(h>85QNM-3)X9DY67=2h zOu(N^6ohy{+PW+bWt1Tw)0R0x`CBR3)h3r#0?8LSAu^!XQt~TiA@^nq^!T{9{$+=iAn<`Sw9q{&^)3{MOFx zU!^p%)iST*U*@MtAjlJ~T^nozFr`X>8t^+Dya9n=UP?+{F)4=C%Q9{1z%Ce?vfZ@v z{N~3Z9Q?~{xzL<#F#Jnoxj_Q{XKjD;`%qkHEi6$2VOP8y0`lEPm}@KiyJ819`Y1)? z6s{7r21yDiuA+WioT5VT+e~(~A=!swQm5BeDMI9>lqe-VV64*dPlZYQ%|2X z5u=rO<=&Jc8jW!gF9!$z-GrPTDrfj`l#*(`R$NV(>rjtB`%^OT9u+uqx1)qBN|oP< z28}nH+7Nyx>0_B{owbqDPE%)aWeDT_;@`E_Zdj#L;74n>INRtpVS>phuY`ogfxr}!~VUPCf|IKbPSZVGUom@S}-|9mnep99<@ zXJpa23!ADy?nVo(%?`Re471Pf%fp@KmO#OumDmKV*3)jmUM1u;a24D0`G$aAPMzuJ zGWI1v5U+~&sbVop=%U9TRKFQeM>KF2P6OA-BlyFLfELv-)IQtCU*k;?qTM1xSy3%G zE3bz}1OAds)KQ~!en=jTGC`o+CFv6d28-fx`lPTJBp=3E^Z7=%W+@H}$a!TTGgO@A zB3L?^KAlBot$yqYuCk#HPql&kMo>D5BXm=vRYJa)%MXtxU+K`J1^=2_#@M#gVLQx4 zRYHCi6V9_PL^(}0qCF2aF$nLO($2zyunFgn3-Vs`mjA(k{c}p3j=yjO7j0=90uq{; zG+`)i34yLz5l4Aa^lSk=_WP}J?yp0OAq(DECjrTn(5i!W9Y#Wpt6!rR!VO3mkqlv_B-EnUn&U0cZfh0`1C zabL@`<|9521}+>p*Rw)^69`e<`9!M?aKolROs{PGhxDGd+Jq{YwE|&qo8q}gE{45@CkYHepa-O zg;3OQ&%yJ$Moen7;4n-zP+yifl1uyo6pxm8N$mI)Z>}zsV;oPkj+Nq4qU?OZxd|;H z&>cP=xw0iHirhmZ{aFb*NZ*qGKG?iJKvr9CVxiStQT0YEf6x(CHzxdY_ts#7BT6 zK@`$%e!k$pyq5sP?ACAjRUpNvJgJ53ZJ6g0_}Dq3mQ;^*QQgGBG3;E(pyvY>f%j#l z(TKCu%pL1p!MGG%E?IDedR6c;9N=eXl=sSU(IGQjqNzq4$Ql>glj-Wy|+aV&~Jej9eU~+V6jS~qUh>=coYgQvkI?4WaqQCO! zV;(FJTn(R(HCkzO(IB}jY1E7R1wUDUmHB~3OpVHust!ao3QDutBd6Ggo{M88G~~e) zgGrHaRc55zatN0WX0b@^l6nF^AxEfstFphFbAEC6y@H>e;hi8j;+jQ38mc02$Ukf; z|2)-h&fye!xJGq*V;PuR#p_#z+nb zcnkqiE%SSyV^_k%!2R%uohGA|e@ZVkTA5q_yYj}WKHCZ0QTF2-_Smr7Dna1_LO{~X z99_4}`sz*pi}Ib+nQtp(N4{DvA$bG;S1p^6vyL@f)Jo_r%6MnIa1D{ zVINe(yo42G)euOC4V57eLs%;&YrE^7`zG$cH#@^~Sx~@Vc*#mEhLY0b^cl+$D{v-j zm}|lZfAyBJJgXluFg1ed!3Y*cRYFFAMuBIP8E) z(WUOgM_7Y4j7_MCHbkQkGDE4{r*H$J;h=MSD ztGV#F0zY=2SeLDM1wy1h8UoN8tC2LeX<>gp!Ainrrto&88r{C*q3t-*X@-?0<_?KxRy_AddCFA2tHqFvc0g;NkJkkyB?JsvOm^)>pawjch=B-%nh1Ae zr~>}_m4oq}lH>vGU3-r=iE+&vJj0>~pNCPU)ACaA-?&&NRHTx_QALE71rpo)7yO_u zmh3?ITH$F80gN`52Ss_rO1G#bH_?f^d|4f;(>Vq7LR`1bnyh4{0dI#}lBdqb4yy;8 z9`KXqJe^Je%=3@l{N$%^{rvyB`Q=Z(_sM_xkGKFiYf?=SNaIZ-;>tMMXGx&=*YAse zkIys5@DyrFu$krMtTIN12tSn4yO`GZyoyQDsP_R0nW#~Ke<=o_H4M_u(FGFjKEvW+ znZZ;WpLVil-41!uQnDJ?goZ=lyGdck1)!j=HCX3yGgA|6xHZx;0hx{N>~;6i9On;t zt-l!8Io-*hqopjNF(pxell(9K=edR143qm8@I_OAkVgH|EGD(gPL_n$SP0Dnc7FB2 z8&DR`DrF&+bDvDym??Cn6#F1*EU=YNG8$eW2{Nywbt=Ip+M$_u3VUbtx_Ep#VJJkQ zh$H(L0`b&*63P8g%R9O*o;nA&Zf}N?=vwm8WwQ?47|9O&Y|%`1&aP?jpKJOBKiQU? zTPtl9F_X~!7nu>m9g-Nt)w8URIcR=E0rvrZ?#TG%Pu>Lozxc_2`1$|wzY+pqNf(&( zl@KlHp=D&^H>1=$Qg;c#sdNzw_;Ca%%_-vF@^4lEc6}^Q|G<^yF@hRz0)Sp12nWip zh=BkYib@9j^Xd-0{Jyi$Ei#FEw!fy9J6?5)mN%i8bCE4q{4Jhmt#W_3M@QHLkO&wK zkB9NB!N8tNMsdA}YV_evhO>m`_6?r$#6$Vc@9Pv3y`iVsGp!>8c0DRFm=NGdgv2Av zZM*KrS)5y2T?->-5_CmAi{zjDmwyxdb3@JdTKhp+ewz*dyNVdy1^g^IinpX%Oabyc zwH%fGJZMR*Wo|MvTuu>1Ta>nw0~^IstPSQ93&+-=ZdMUR5@3%>IXzd_!qU0ScYzRL zXoBOlxl-7qZWqA&TvK{$YMAP1S8faYxQQM@u!%v=WqlZTi04V}Mku+U`1huyAKyIt z==&f4*Z=g3|NXBqDU6Cc0-jm##qa7a8Y|>RJ>)6ariu>Oc7sQ1Z%#oA1WpKWq}{4c ze*6&`xFw{p2mgrzXSH~?TW3S*o+7{HQUbgRu4He2LeBj&p~o#w*4hPsUURb;WU@cG z5<_Kn-~=DNQkhVYSjDaBI%N+1g8ysqBYc?6sF`{`4?-aeI3w8YrsP}?qhRAV+4tw* zTioJYoQS?;WN+Sir&s((jLK=P6;h=i4#P@d9^^m!+wb^zoEQy?z*#ts+LcdyatK?m z+3la@CQKc5q;7I3O(bWRc*&oobyCtmVl_>$Zz*EPOgo~$NNFAc3~BKxKB9q&UB{rB znq>zu6K-q?cib-I8(Q7xF|DGFI5QMhvN!2^_C@f{F}dF+iHOae&{5AoOFO9)6~~?mEal+mzzcvxZ8kd zQ#$qD6k`p6Uej?tVw%`sLKyVszL*BDuWqdJ zSyfWB_t{b8VBzc*1ONI+;BkyJWjHr$)bB0xP*Xl{4n+)&94~-XykH7=`i?SR?sn<& z?99gn&!m!MPniEHI%Y!m)Cb)l1FkvdeY!rphj)JQlfR_>!{7fEuP_y#5HbWsvdqju za*NGde)V3md~q__i*w<3I|?!pn7G&w@G!tI zSC)ZdQ^rmiy3}kMon=67mt&(8E%(j&VVttmDy1K*;&?~un+ha!O7^5dIEU8|plP=# z3Zyl@(CyS!7tlZ9<37(`F_bHajuZ*Nm`TC&AN}ar5C8Vr-~Nzr0F#piVu7(n>b)XA z;P)7Ug{my6Uxb4Yx*dTN*FcN@bEJW3OI4Q0f+SO=Xh6TE2M$I6Qh>`lq=O&7MQTvB z^c>^sM_Q7#3(@%Z@EWJD<0K#8)T*0T-s|XNo1)iZq!fG?AtwycJ#1#eLP(@4_<0jN zm~QAw3d+hhWDW?OL;aMyz1o`2T(CuPlM&K-tFC9&9nMJmAP3e2^ z02WX}KBQJOMl4_wO7lsEOQgh%lC~Uf$OrJ5N@VG;A(kqLTreTfEWp8h>xmL<%4vFo z+Xeij{^9?}PPUL{ah2DaatA5+EX3G{%ySVr&X9`NVls z$iH0bHLr0!M?$~ZH)uVU9$fA8*Hq0@40lNWd+<+4hX0vOdkUxPIEBQF01WIkqLG^Az1ozz@ zlulymT=vRzJ{^wl44*4SQZZ&jV9Fb_TgFQIOFx=@6H^yA>N~^+hs=YV-sX}Smfr$? zezg;%QKB5TST_7IX02Mof*cMzU;rvaepZ2+B|#eAZy=i-GZTc(Sj3<)I$}g4928JZ z9=z~aDI$=bHC}vIG4OIe7l%bYhAj=Ix7ksXtS9(wMB=TY(SeE?L6TX9MlK75evvRj zM#4N})+opg@*Xdfm{N!Tvp%C$v$DjIdyV5@p2v3dtjH!S+-;BLBU+cpp2XMd3FAUW!nW(3++z zflF3eX%6Vb)6n)4A?NM_x7?RKvc9qMD|{IM_pJx9VM}@~i419prYwpo559Bl6xtaW ztW!LNK{IaV6f=2@kj*KcXmicbHAdqaqEb063_kcli)2U!)X@&% z>p|+7x|?n}w=1Yv9@Sz}i!L%0vAh`#bUCN%bk)qB2}qd45U6br3m38ZR(v8h0yO$2 z^++bg@BlcNq#s*hKX340@qbxm)ny4WgGiHhel+%sJN9=R7)7UVRd1gGzpuI0gGQ|w zNpRRinG-Kpy6@Jkaiv~pV{|*uFSZ}+@ZkT#Y1#BnhleRvYjww2xU${^-u00ImAMHP zuAMoh)?-nE*4Y8>R+rqIlHrOp&+S+Oi~~B;yehHgfTZ2H24f}{bR8^rzlPlGu=p?G z9}*%ACz?KDc41%p-^Q&z+N>R|t)gj|j?-I0FmwZf1MJfV!wAbb@)}?#(i2nDkNK#@4-D37ZJ~&?=n|Z?9*aG# zkv6!(Q3Mp36jrY;;j5WRac(C~yw)a(mzfxL`p_)Q>roKaarhmy=ZbA_MCyY46(Kix zFMBq2_Hh7m*T-t2*rxz)hAm4^g5K0%?4ttX(wOF;9rh^)@|70OnsX5-i)J1dYlF%3 zf5BT0&N46jZ{^>+4M6KIav9i+pOltUY=uKNY*hCk+@c_*;J#FxJLFh?)W8v>oC5i+jQZyPp%{jM$?bgpg1Xsviv2PT7qKx{JRx_F_9X#zGjiQT4>AGAa- zXZN(?&?9-WYkwm$3l|_CC(^=T;d5{ma^sYIICF%;AaNle6Dhf(bR+UvpE4{A&9*f|lCqZ6xDfS)vXOjjEh z#Xk(s=}bcLR6z(54Am@I9|Xm>&V{)I|K2-{g{EVF0jbR^j7nv`NeIMEr4DCC+Bqq# zNXF*qyZ8@s#Ls%%ZU?$GZ#=Hk8wSjHKQ?d3VT9;v$FDFxm)~eiYLwGEcEo zgMpiU1`nlQgq#*zrE_JdvNhVi);n>u>0b6L0<~e{j`*$OBn8V?E`aVPf7FR{!vjg{ z*f|`ip~kl3FWucq5S9PnKNmG(Tdz=fVV%vQ%>t+v8sq}OW{Sh_6Celqud?`kW1m4w zeaYHXo-L=5_G|cO9(q*E0lXDaVrsG*G6Thwnsa9s%+~cH7EY-}HE%EGW-pc@kkzNC zuX!tp(q_GpS0So+si1%qls#((pA{mH@J9#2fQ=eTBO zl!O3bTL!j&;Wtz-+AsX?0@{J(Xe!c@9J{oL>n}SH8vd%I`#RT49c6sUrC`|g(p_V0 z@o?ZIW4jBp1l)BfXiK!T{;0a^)N>d>Kpmi?PihgQYXn*M_DVtw9vP$FP~i*&C49>lDba zmFJ1)6Y`)!ekU|{Sii+{2Dq?@nv7^7$d7SY+*YKH9BADq$Y9#-N)Ub#6>`NA9dw3iI0i`=4X>O7uH>Y$u%(zX&>Gv_h-sGO= z{G{^qN#=k*_`e|#p1=BC8uzM0lJo%bJGlc|9U_nu-r9LCNJ-k$6vGz#o6W^%I@xmK zYw!rqTkOS^zX$wL#JY<&gMYJX?)Mo;?DI&Tel4tbtyb%EbX8BxSdGu z&vIRpSUDkM2?K17?gZKtFa(kCj(?L%${xYeQ}4nW%vL zU)+72))3&ZEwr#+$XQ5FK_$Q>*sOIIV+n-yNEyjl65yv%PM{rLXpGcf`}%vCAFZQ! z13Zq#Xx9@KeT0iii@D<|_^1CNF*^@!*3m;d5N3X>mjbnJ$_l_7>G8=agg{#}EJ=YD z;fr&t-#~FDQx1`HJ0eCXkcxj?6J1otwqolDnzQNLB?M=lU%S-I3SWzvm0*%}2cIMG zm0D=S}({yD9h&3@&n_Nv&xoet%>?$$EJ@?yMlk# z(tC-#TgUk-84#J{$J#lNpf06A&0<$yjTa0e%Q@qVXHAi57({{<71>_P#Eo(30Y|UP zWSD>|2SYNJRof6FEdi@N2NHQ|x4yfq;xuT^3@b0^KkF`cc8~$14sDN!w3E~{^B1LF$L~cv{~Z< zc)dNaB_GemWIOlSM>`()#|~vnEU#s*5^TI@d zSdyI8s80zP7R4ztIaY(5AxY$-i9Zt~{S47eNtptFCsG#$y zCkX+-k8G)#C6-ZNikL_7OCwLcf^*>c8vKVC$Y9g{>3n9FvAOo#%OA|hwp<*$jqe6U zsA&k~C#R7dRD*w_00~in(6IhFe+bw#zJmskY%kA>G3XssK*d0#$y#CEau)}KeAdJ$|5zXe^Pl{b z_I9^d^?EwuX+S~%7r2B1!75VC7zw4^X;zF^ExZcy+Xnx982Awa1=3XsG*oZ5p*UV` z?Xv}yL)<>BVYqb{6mbE6r^(hlwg|xKga07&I@ioy$;Z7^VH>YQrKPqMpQ%q$fMrHG z>(7>Rx&EtCTC9V{^3L(Kp=Qi(s0pYoR>gzw1;1Z$?&80pojH55>Sp%zFJesrxycAu zLRK_D+m?QsD34h~|D9t(HMPu`Wt_6*V({OT+ElLk<^N3qh<$1bI7%Q=0Qhf$IPfnG zX0a%*+5vDPEl@0V<7k4N{A&t6y_TAGz-H1pRyYj-2PN)?^ujar(|H;FAa?u5-~~^7 z9sK989+~U8QvovfrwHtpsv_U(!cS+xUqi)xflvu*Tzm`gx51yUjQy)~v+8m|Q43MI z6wCzbhdUZpChI{$}85k*6!WBee0j#t96LE>5#r3DpvZVYK|ckDPv zBU2xnpC{oarVzC!mQnyeOCR_M{P2m2By1(~$u&fMI0VUW-2k$s>^1n;V%m-Oo|1gA znRN6`ATwNwRqC0F)VQmCFwxApuy9MYC_CQNCI`KYSvt9BQdlF8VGUBag}R;jCX4)p zKnPhVLK@f&X90Wh&pz;cTMPs?4%#>17N|=F8eal|mXV)`fceS7ro7%aamALUmqaKY zoTML9)TaYWhF~Cu2xA8%^6=)qT^_8_AdRC|G-|Rbi?5`VEOjDVj*LMLs1z{AQtHKq zNMb9GMUuImer4(lK9lJ2TJS%0!qhNgJ`;H%WW3MB+&%+|cD~)_tc>gNMO}gFq@$3C zuY=45!vZD*BBZ(XFE;`wQ$za>-C~s}V69IaR>39|qhOY^x}&f7N3R-TgmGSG=b>>r zvCrO9vsciftUW90q2onU)2>6)gKnLIM4!fn%O2y1m?))SiqD)F9b;-^lTo&lahaX# zf-q8KPz)n3_RO3PvB5tJCQN>5L;=iDBzz6|Txigo9USIuJ0Har%BMR49&MN*p zsgd(H2lb6diX|fmcYvaXRq!7#r#85BUNv{#)Sw7Nor^^hkvV1;&-!A?yaQpq9hBa* z!|+V;UyaO2qt5W(L~EGbTk|Dp&PWRk&*#&O&O`4vNKT*|O`Q1hBVb9<~p9ue0` zrF3CeafC5Ddif!(N`*xO4?elLFZseqAKIVTWC%=sjsJK*(?HjnYDNy$whj$Wg7Z*) zd+Y0d-au0}*N4?QYpu)&of5JHG(YalE>EcbcbbYdk%uhC8 z)uI4ScGG%`pLrATSJ^e12%NK))*RO)Wm^9|_{aXnT>w*->mHBc2Q3*%IA-TKyWbK~ zv0Dv@6D|K3y-9(t(gGE==8dmcO65p(gaD^FMCM4_gX_3)Xn8X* z5L#gwzLJo`Zx_sj9J;S#CX!c{kMCl!2qO&IN+x5^_*I0Az*MufSon=xZG`ZZgWO&^#uAzXFKEi2_9$kJED< z7a|2|+GO%<3&jR$!ipYh5IR4quTgVc7UoH<9vz2u3!7wBBQgEB?T06cJ%95f@b6|4 z=+U&EFqsG%Q;S}88G2FESghcu!>)FYvjYA#pgjbKBZ*xVNM8g0qC%4COmp!MrQo<4 ziV291L3@qosPm%_{_X=;MLXr+(D432rb5UTd9dd!T+bvl`+~eSox8s=ICfxOeBi$% z6R<`7EZQ(lMoqqID0x<|j$E$Zqom5RO|JiP6C4oKdDaBG8ba_gUo zap(1elLHUi34GWY@$qaEv^xX)<6)}cA7z&o41oY((}z+Svjkn&J>smjSZv_3h3u(hEkQ+_U2b+>B5 zTxcP73xhE5f+{Zd6t?u-f6qI=TKwazMMVoLdSkJa5D<8X3czG?ukT^3v>IB{DDeBxQAUzcRozkGh`aGdFBS{ zD^eajVwCNUlpKRpuG^p{{FWt`MQ`p$Q+HGRvP6O_{Tr=J@e(o%-6#@e?UQM;epCjZ zbp!c7d*dU#k1*oD#oHpbFyP?CY;)6IZ#pg#W$N7psD`#G9Qa?7*MnOZVcP>>ywT&u ze<%yn75sK037Dr)s=sW-4~HcL+~w62P*WsrSqot$p5kyDbhO{ zum)x!eGpavLw5xK$}@%5n4N?Bv@UuMGgw+s@GB>nxo0Ngi4APRj4+B{H3?qDK$3t>r6L4aYyeXaoX7x2| zu=LEo69@n}rA}%m%wkh2Gx+UhwVVX1zY;!iN?N`_^}82PSK6?1ODNo!H4UMo1QxPr=MAS8Bb@Cd!$r0Hd*~44WGQ$cB)e z?RqD>^%%Vol2=fSf*OCk!w`%P2pLgCF@0{aVLc$xbz>WE_9t@u?dgqE<$U(7AO7M` z{+gdo`}zNH^Z)(xfB%2~cmMAH`S1VY|NZBG^$&meSA+u^Ww|@iXUGo@@f7}r>&$W4 zG8zHIe`P5CkpaS)cr^2BPmC7ic)1*D`4+`f%m``lUnIyF;v{&Bi+x`&mrOjMYZNMl z4G|TyBM(jEr^p2VI1~r@RjOPJOG|VI>LSnv@&)r9qlxzkjYR8Z8*{TfQY|MK1rPA! zCb%;d?<{(peZp0%Q={0x*;%S~2oX7`j3G7-y7piWmJq2WKUbQV&f_v{3+&kd{PTbDZ)wk8eiKBI zHTc048ZhHufJ)=dff>9|>L9?65Kt1M7>0aMgQFcbJdgkYJPWGapGuFjhXTblnfBCeOovQj$#qLjsdE6>byNQhVi*8qNz zlM8%$JZLcmgb5iXZq2yiqIxs_ow^jQu@d+xd-F;dHXg$^F~}t4c_8z`Lrd0}L1rV% z5YUVoXYlV3N8vZqVWW5(F_<4R&Q2jdbkdhAo~n6Jy492+5Zn$Y*FFQ$0C?!y?B>Ch z5MgMzjM{@(Hk|p5t)`(S0(l_S#THsepT0?~1^n@j5ob^rHcrw{@9PdSMSO>+sKA*l zFqsAaT+aU0_dj4cS8BRj}U0XIJ`k5 z;F0!Ztv{6X6zKH9IF}{mNXE@?J-5_Q~9HPH7Zqa2VApqKi&W zz=4ENDOVe?nX+-Gz)Wz?;{Ws^jrFGB=&(KXoLWcL&$E`h$1dTgM8K=_o;@iO@V(Jfq+$^ z8u$=|{PLS`{`?R4-AR9RGT^uVIamn%r}2ro=7@sWQ%GR;gm8uTx0AZtkgv2xb_H7r zyLxkBR8z(@pk|B`>49?V|@HPe|u z)Ib>g_mtSMmPCv4Kd*R)5J2VVn;;eE6QPl+F?;peDckjqcMJvLTy~!O)SBX-y*CFH zQ~$hplx=LS=-hP)ye~5;Ku%bNE{HE@Qp7@w%+#6vR?WdkMZCH!L9Oryo%YC_F7u}(06ZxyH!UI|<3j#q0rC|1e{uIcA@_twTR-#( zNI&IKNZ;cLC)w)hPwJ4B$~hpPQ>gkVqEhKeAj7mGXQ)*mp-2wPEY`*Mg>6>GWm+&)SPKuG_JNvE~eVTo5aPT_& z*X$|b6i8!p4;bVd1ywWmo9r(vbQD84`2sR2|5I8-&VaKdCjJBdt3=?4ouyiV;Wp=Y2Y3GY;Kf}Sbhoq zT`46kURO%l;bx|2X{xn#E-<6{zHyolQ~AtSmjm?FFcmZfc+Bq0=(>>z2!~Rmc|Y zatdBH%R?QylBK!SNQS_y@L=J=c2Ke92lfp9HwEl5DKO|fikCfR4GL2i@Y(N8$}oMZ7xj2XErY=j~d55YjUS?zeI7^griH-Yova(7^10Lx1#k;T5xN@Cs z&u5-<#be2N$d6e7dxp;un<|b>*GU99u5gVJz(!4xfRY^4QUBJ(5AqD^%-{$F+&3_8 z;$R41kOC&Br~-Q7uVEXpA+~9}G2*JbOA3x<3uZV#9)>WngPTLpeMr8FbS7R7$yXk8 z00v+u1o))L4_%8@Buo_G8bg4yCP8nIu9a9Vy!y$BiQj;q6BF#hCSu!dtYpX^oQxe} z9Lc{ek+q}ai?&=oAVJUCLb6r*?^z+D<{CqZ5of&)@qi650OT}u2mET`<)?Y{Yw8Uz z5I9E;_=y5yAv}|$yfYL>Ea_z|^-8=Sm`{Mmj4f_=6$t#m|7L;vuT%N=mz(rm=B;(8 z*3*y1X~7@C?2Sd|t5*(rG-Sn&or((7Tlxnxx}ozxNj9 zVl)Qn^9@Wu0y`si#+P%;=MlBbCd#9c!|J@T4Qv_(1f5x+r4(;)y_te0ukP_ifq_78 zB77HurZ=e){2M!?JHkwxDNO8p;ISiFoabZzw8fP&Ac+alv8$%SCEA2FCm{#0v>g5Z_;4#VKh4&q9t=)qC+YKA{4=*jqxizhuUHA2Q}%PbXYC^q?59*y z{Qpz%&lT9K=o70d6210%v=(#S*lPUYE5Cg6oBV9k)z5Y)yb%=e7yq3XsQA&C+V?Gn4 zn*$i4&4XJx*G}i!*Q&=XChN90jf9}3%524KRBJK{SAEWplgI^wGhMg ze&R6>lGetd=iKCYmi+r`l3iT^f!7Q+xmfQn*{aU+|AjOrhaxJHGYYcB2-v|lg$+ZC z&n&HAQi6`21>n6cn*MYVX~^BhmmogH@fE6 zsmzSW5{eH(w^oED04@DM`)p(?{G~3#2UxlNXHlfU3MI6anWx@|&#rdtL9Xf!^Nx2(I8v`7`2chJpC~9(m0>c3bQ)8Hb|gBHV07O|w(@PNpxUi7 zVwU&#OVVRTl5V1Dw)u11%)+iLaI=0e??F*zy|x=!}5`O2xV@5yJboq9rEeK~p47aj^hrVOvh&|)7w(QoUTqQJ(y1Pc+ zqiETbB<8P*mMYFb0#)QExI896lKhjzleooaQUHcp1##R&>(ZAh3#V?D5Zl53uww9^ zQP8ybH-bW&2UKF!IV+e66;B$KEz6U<2LIYwi{<`1yps!pK0`Zg9t*D`CzB)Bz9mLa z+28ikhVnn)nXk6KO8jQ6*jUgMQ3vB(1@C~$<&NS%%NL!(&o43g)tt*%CDp-yyu8W^ zuvyxwYw(?P+8pgAY(0ev-Ta0rNNrAw9-oir7NQ7+Tmo6MXqif=mos`&TkW5U;{T`X zZF+6HuJg>_RX{ln%LRybP@)|~lnoTGQQ$9Ts(#{5`w(Lri%wx*V} zOZt0k7uc9(pM1N@8wr>|O8=&Voe-mV=zQo)cnHOB9M<2yEKv-yx) z>&5wuE5UHYo6Fkk3LL+MERn{#G(yuf5H*N+!?B?OY$Z@>@K*+arMDmE#xpM+gil&muA z7mCp+7T9oOaFQ-3?Wu#~ab?T)5dah|1r;q?=v{9)q_o;YheRTM|Ni!E*Czu(y_yov zBq~8ffCr2C3wX<#Db&iJ41NLsgaC&I#s5hdT2E}3bPka)Sqr=&s&{U!P^W&hM_=sD zaL8!j05VWCE=XTFur~_Vxh65tK@3uqh7YX9A|3lw-KXsn94~zS-Dj8#w1&4{=cR-n z{pDYO^249=YBsn1NUe6?a>&1`E0e@P8iLCtnJLF`)jv&Jk_jW{HKjk%1lJB%rxFAv zV3~4=bL0=vVLl}}A*KwL3||-U_P9Ve8FM(;G29dteByMx=8vUbUqb!iD<6IMr>yq! z9$wzS*mv8d{=^P?8ZzNTEZ_9XOJLu7#O-xk>XhW)daFz4fuGDn6X3tcYZF%RsRn`s zKDmo8RZ*}Z$-_S|Kb!F=>_QL!yFSPeb;+}w6R(M`^!KClWLXXOG=11_8qyrYKiY0x zW`ERDQ&o1PvjuT?Ar@w}_#huj2Q7>Z`NSd`VviT|``yg3^ZX-GK$C^6%<+!f21p07 zsX>#i3pgt>I9aF&`>X*;tvBd8_zxzt$D>b*UoW9Ae=_=3y!7YaKg`C z{Z)1~yub|nXRrJ==S^W*Ui1e3fBnDxAD{i;7o(01(+`Xv2}3q*!-5We@% zC|3Qa`vGlS02wx7wvs~#4TyCjukR4p3QOtruP8wsN-xgsRL?ZzWjB-ji^B{5WLzxu zf?<|=L)4Ff{nNL9O7T66@3{|z0-gaH7(AH{f4|YX~U)!oO5GP!Tiz*C=z) z5)#wL$1kE-Tq(3hizEq*bjSx1o@!rX5XkRJXg~QSMloYFUCC02u90y8_;>0UUrV5o z!DdL9=E`9CF~C4hT_7A%nRTl#6^$EQozLj1@N<%<2&W4>q?%36NJTV<;prEHN;)WV z7^gh`@zdAd2jQTdbN_zx=Chx^_O++4J!3d~_jT~_>wovR|M+kJmMo|tJ}yxD4IK^m z6`%=&AS^HWFUyE(I9Twf*W#bCMv2`kXVy9ZRz)dw3RM?@m+@jOYNq>Gq4@7uVA7$u zKrx&%-1_c@IpCC_)74(o3nYfJ@;-6M95A!(A#cs#mFO?`g|MIe{ErU!QB>a>Vkq%_ z;=Txm+$p#CFOUxc+Xds%&7r13Zs=>{GV03EUaD*wd^1!D07}B>1X1GxN3n9RZBY`8 z_`C(rg@5yko2Db%ktBdDP_xGves(R`DIZ*g;dujTgrYiu@v~pUqB_9Ev@DBuUn7Gfl^L z@PLpN#%PsCSKRvht#45Xtb&Ji>L>5|{^j@Ibl=x6zVpcse-AGJ|3Dqr`1sWiDZ~h- zAYw|bX~9@!j7%3S4x5VHF#kk>bU(Zo4a^dxLq7NxKrd06>8HS6h+8 zMa$fX9;z1PZ%SO`>v2W+;Cys0u96e>%kj$VVr!1TaRFe1CfVRr7hr6HZqak`Ul$-- zs|l)bKDh;eWfb`Y$icS;vgE627Z;8^Ck2XHj(tIb7hF*+UYt>+F0Yw}VE4L4`2OURUTR(HO^^F!uuEX&}? zSklxc(&aQO3A!3<;4VXCcBWx{RAiZ^rH;T)k@&A_Oe*e=3tb!v*f)sq1z*4=&y9Lh zH~}%5b<_nO_(&TK-Xd+9GYsj8BfvJN@TKBN(sTuVil6K*MxUWpAKwuC(7R6wnQ#V* z>b!+t>LUezA))eVOBYMzYWzyb+r9_`@GluAx2G?08AYY(SQZETQfb`xzgxneeMT&6 zHyJ}cmfV=bm;aI3{brCq4|IHyRcsN+4ulNW$P-XI@GvX5;}~m zu`5>mq8%qQk!N-e!KTZN#eWc3qdUuyurm3KDM7YUSetk8nJg$19VC#QCv124@0Q6o z8Vd8@_$eSiq2$&D{QW9v=;krfb3{OLo5d3NpX?>k8MR1*L;Fn+RPt5AjWtKeZ39`= zF8*%^2=>LHP`s>cKOx{)d^8_I2=^)y&Ir%5JH7b#xu+h&V4ghds?2kCs&l48lS3wq zj<@RU+4=B~|N3viKhs2IGd?>B$>-pIh&rYz^X#W0b*Q`VFlxd8B&JBh;U8nP7t2>> z^>Rgfmwu^RL^`EWuln?|aB^#)5;O_^L9F2*>-+6^H5@M!|6q>+T8q6~sC$`NS#6{~ zCBtueCJb2tdnBS;zoX}5$l4U6D0#Oeb<>&yx&!9jIF}G0N)O+bf#WHtW%*ncg$9MC zjx&23#Q%uei4I|-v;r@TbT06+@Xvy9JT!jlz@ao7ql!9dfL$Ii3**bUNdwS%t)nTU#=25Fg}KwUi6CB6x0*;77t8lW zi@_q#UQL=5uLPoQ(&$SK-1M8(oS{nD7@d@4<~W7VzVnMuzV}O#A9jIa0zW5lWJbufj$HKx>)qzUR*>(ztS~b;PQg>T@6$x(t_mBiw!Q3ycOz1 zCI-Q9l~7CZ3m#FE#cC)sZ(Z*@O0-(Mm00W^5)~NcsU`(~3v=?gz$x{DhJ(l))(XvL zD7x#IeNN{*I+W~J7YO+IgnUpApOcZbT4^K|gV#kuRin;zLI2YLp_0ZG)-zC@X; z(x`fxOPWpPmd)Qf_GHAwyhp||w@bZFX|hgA*~DJ`kE%~vmMf8 zour45r7WzY)s+7t2fj}!KZK}r7m{0{VtC61yhaC_Tapwx1t&L>$FkFg(sRYHqs4VY zs-nVqoSe?G^UbGt^6H|7Z)~AC=1tAieDPk~c1YXiq-FTflMKOsKZDh>&;z@~3gZ#V z5FUesf#P&$vaG>C>{#S?mHe<}FdRzZMl=A7(XbwIKi~&2;@=SC@V~hV6$*y-SU@s4`+<`KBW(gf3_W;L$mk*47)Ec70%+aO;(upvI&m6b=m2o$h|D>6 zZ%J$&*kt**-a57pCRK7Htb}%>=fP)c-WJN|o!C&~i=ongc{FdQkjm7WFzC5ap;h#juzS#?y

GK8 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 K>GQw)JO3X(c8^d1 literal 0 HcmV?d00001 diff --git a/files/water/water.material b/files/water/water.material index fd2589ddb..673bbaf56 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -45,7 +45,7 @@ material Water/Compositor texture_unit { - texture WaterNormal1.tga 2d + texture WaterNormal2.tga 2d tex_coord_set 1 //tex_address_mode clamp filtering linear linear linear diff --git a/files/water/waves2.dds b/files/water/waves2.dds deleted file mode 100644 index c379886faec80aa3b6772a890e0f49822782b33d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262272 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 gsQ~eb`z73kNP2Y0|?iZ|j%iYiX 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

5=oc2ne{-j%I1pSA#|$qc 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 Cxy8Z& From be4af711af3ee7668110b7d838c275432b969bfb Mon Sep 17 00:00:00 2001 From: gugus Date: Tue, 3 Apr 2012 17:30:19 +0200 Subject: [PATCH 019/185] NPC rank was not loaded. Not sure if it's the right way, but it seems to work. --- apps/openmw/mwclass/npc.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a94d27d..b98df79ef 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -53,9 +53,14 @@ namespace MWClass // NPC stats if (!ref->base->faction.empty()) { - // TODO research how initial rank is stored. The information in loadnpc.hpp are at - // best very unclear. - data->mNpcStats.mFactionRank[ref->base->faction] = 0; + if(ref->base->npdt52.gold != -10) + { + data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank; + } + else + { + data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank; + } } for (int i=0; i<27; ++i) @@ -281,7 +286,7 @@ namespace MWClass void Npc::registerSelf() { boost::shared_ptr instance (new Npc); - + std::cout << "class npc:" << typeid (ESM::NPC).name(); registerClass (typeid (ESM::NPC).name(), instance); } } From a268b89239742ce05f164f0706c8c765aa01ab6e Mon Sep 17 00:00:00 2001 From: gugus Date: Tue, 3 Apr 2012 17:31:41 +0200 Subject: [PATCH 020/185] changed the way NPC faction is checked. Should be the same way for the player. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 50549f4a5..1e6faf292 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -39,6 +39,9 @@ #include "../mwscript/interpretercontext.hpp" #include +#include "../mwclass/npc.hpp" +#include "../mwmechanics/npcstats.hpp" + namespace { std::string toLower (const std::string& name) @@ -474,22 +477,18 @@ namespace MWDialogue //NPC faction if (!info.npcFaction.empty()) { - ESMS::LiveCellRef *cellRef = actor.get(); - - if (!cellRef) - return false; - - if (toLower (info.npcFaction)!=toLower (cellRef->base->faction)) - return false; - - //check NPC rank - if(cellRef->base->npdt52.gold != -10) + //MWWorld::Class npcClass = MWWorld::Class::get(actor); + MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); + std::map::iterator it = stats.mFactionRank.find(info.npcFaction); + if(it!=stats.mFactionRank.end()) { - if(cellRef->base->npdt52.rank < info.data.rank) return false; + //check rank + if(it->second < info.data.rank) return false; } else { - if(cellRef->base->npdt12.rank < info.data.rank) return false; + //not in the faction + return false; } } From fe63f2b2aaf0873fa57c8ae766776c5566da1181 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 19:10:02 +0200 Subject: [PATCH 021/185] first reflection test; removed the refraction render (we'll have it for free using MRT and deferred water rendering) --- apps/openmw/mwrender/water.cpp | 71 ++++++++++++---------------------- apps/openmw/mwrender/water.hpp | 1 - files/CMakeLists.txt | 1 + files/settings-default.cfg | 2 - files/water/water.material | 61 +++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a6479c401..bf40c9567 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -9,7 +9,7 @@ namespace MWRender Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mReflectDistance(0), mVisibilityFlags(0), mOldCameraFarClip(0), - mReflectionTarget(0), mRefractionTarget(0), mActive(1) + mReflectionTarget(0), mActive(1) { try { @@ -28,8 +28,6 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); - mWater->setMaterial(createMaterial()); - mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") @@ -48,33 +46,31 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : // Create rendertargets for reflection and refraction int rttsize = Settings::Manager::getInt("rtt size", "Water"); - for (unsigned int i = 0; i < 2; ++i) - { - if (i==0 && !Settings::Manager::getBool("reflection", "Water")) continue; - if (i==1 && !Settings::Manager::getBool("refraction", "Water")) continue; - - TexturePtr tex = TextureManager::getSingleton().createManual(i == 0 ? "WaterReflection" : "WaterRefraction", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); - - RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); - Viewport* vp = rtt->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - vp->setVisibilityMask( (i == 0) ? mVisibilityFlags : RV_All); - rtt->addListener(this); + + if (Settings::Manager::getBool("reflection", "Water")) + { + TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); + + RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + Viewport* vp = rtt->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); + vp->setShadowsEnabled(false); + vp->setVisibilityMask( mVisibilityFlags ); + rtt->addListener(this); rtt->setActive(true); - if (i == 0) mReflectionTarget = rtt; - else mRefractionTarget = rtt; - } + mReflectionTarget = rtt; + } + + mWater->setMaterial(createMaterial()); } void Water::setActive(bool active) { mActive = active; if (mReflectionTarget) mReflectionTarget->setActive(active); - if (mRefractionTarget) mRefractionTarget->setActive(active); mWater->setVisible(active); } @@ -146,8 +142,8 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) if (evt.source == mReflectionTarget) { - mCamera->enableCustomNearClipPlane(mWaterPlane); - mCamera->enableReflection(Plane(Vector3::UNIT_Y, mWaterNode->_getDerivedPosition().y)); + mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); + mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); } } @@ -166,33 +162,16 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) Ogre::MaterialPtr Water::createMaterial() { - MaterialPtr mat = MaterialManager::getSingleton().create("Water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - mat->removeAllTechniques(); - - // shader technique - Technique* tech = mat->createTechnique(); - Pass* pass = tech->createPass(); - - - // fallback technique without shaders - // also used for minimap (because it can't have reflecting water) - Technique* old = mat->createTechnique(); - old->setSchemeName("Map"); - Pass* oldpass = old->createPass(); - oldpass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - oldpass->setDepthWriteEnabled(false); - oldpass->setDiffuse(0,0,0,1); - oldpass->setSelfIllumination(0.6, 0.7, 1.0); - oldpass->setAmbient(0,0,0); - TextureUnitState* oldtus = oldpass->createTextureUnitState(); + MaterialPtr mat = MaterialManager::getSingleton().getByName("Water"); + + // these have to be set in code std::string textureNames[32]; for (int i=0; i<32; ++i) { textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; } - oldtus->setAnimatedTextureName(textureNames, 32, 2); - oldtus->setTextureScale(0.1, 0.1); - oldtus->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.7); + mat->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); + return mat; } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index c4d2189ff..61519dbb9 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -33,7 +33,6 @@ namespace MWRender { Ogre::MaterialPtr createMaterial(); Ogre::RenderTarget* mReflectionTarget; - Ogre::RenderTarget* mRefractionTarget; int mVisibilityFlags; int mReflectDistance; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 0a38ff8b5..56c3db862 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -7,3 +7,4 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINA configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal2.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal2.tga" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/resources/water/water.cg" COPYONLY) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d9c908883..914b4019d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -46,8 +46,6 @@ num lights = 8 reflection = false -refraction = false - rtt size = 256 # 0 unlimited diff --git a/files/water/water.material b/files/water/water.material index 673bbaf56..50dfd9379 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -18,6 +18,67 @@ fragment_program Water/GlassFP cg profiles ps_2_0 arbfp1 } +vertex_program Water_VP cg +{ + source water.cg + entry_point main_vp + profiles vs_2_x arbvp1 + + default_params + { + param_named_auto wvpMat worldviewproj_matrix + } +} + +fragment_program Water_FP cg +{ + source water.cg + entry_point main_fp + profiles ps_2_x arbfp1 +} + +material Water +{ + technique + { + pass + { + scene_blend alpha_blend + depth_write off + + vertex_program_ref Water_VP + { + } + fragment_program_ref Water_FP + { + } + + texture_unit reflectionMap + { + texture WaterReflection + } + } + } + technique + { + scheme Map + pass + { + scene_blend alpha_blend + depth_write off + diffuse 0 0 0 1 + emissive 0.6 0.7 1.0 + ambient 0 0 0 + texture_unit + { + // texture names set via code + scale 0.1 0.1 + alpha_op_ex source1 src_manual src_current 0.7 + } + } + } +} + material Water/Compositor { technique From cc4076d42aea6e8009f6505a0cc867532a7c2844 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 21:16:43 +0200 Subject: [PATCH 022/185] basic noise --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/water.cpp | 12 ++++- apps/openmw/mwrender/water.hpp | 6 ++- files/settings-default.cfg | 3 -- files/water/water.cg | 56 +++++++++++++++++++++++ files/water/water.material | 6 +++ 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 files/water/water.cg diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ff4e6786c..98344297f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -185,7 +185,7 @@ void RenderingManager::update (float duration){ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ if(store->cell->data.flags & store->cell->HasWater){ if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), store->cell); + mWater = new MWRender::Water(mRendering.getCamera(), mSkyManager, store->cell); else mWater->changeCell(store->cell); mWater->setActive(true); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index bf40c9567..df6d1a97a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,16 +1,19 @@ #include "water.hpp" #include +#include "sky.hpp" using namespace Ogre; namespace MWRender { -Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mReflectDistance(0), mVisibilityFlags(0), mOldCameraFarClip(0), mReflectionTarget(0), mActive(1) { + mSky = sky; + try { CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1); @@ -33,6 +36,7 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") + RV_Misc * Settings::Manager::getBool("reflect misc", "Water"); + //+ RV_Sky; mReflectDistance = Settings::Manager::getInt("reflect distance", "Water"); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); @@ -44,7 +48,7 @@ Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : } mWaterNode->attachObject(mWater); - // Create rendertargets for reflection and refraction + // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); if (Settings::Manager::getBool("reflection", "Water")) @@ -172,6 +176,10 @@ Ogre::MaterialPtr Water::createMaterial() } mat->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); + // use technique without shaders if reflection is disabled + if (mReflectionTarget == 0) + mat->removeTechnique(0); + return mat; } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 61519dbb9..8e9014833 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -8,6 +8,8 @@ namespace MWRender { + class SkyManager; + /// Water rendering class Water : Ogre::RenderTargetListener { @@ -30,6 +32,8 @@ namespace MWRender { void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + SkyManager* mSky; + Ogre::MaterialPtr createMaterial(); Ogre::RenderTarget* mReflectionTarget; @@ -39,7 +43,7 @@ namespace MWRender { int mOldCameraFarClip; public: - Water (Ogre::Camera *camera, const ESM::Cell* cell); + Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell); ~Water(); void setActive(bool active); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 914b4019d..ea2aa8ff1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,9 +48,6 @@ reflection = false rtt size = 256 -# 0 unlimited -reflect distance = 0 - reflect terrain = true reflect statics = true diff --git a/files/water/water.cg b/files/water/water.cg new file mode 100644 index 000000000..6d5df987d --- /dev/null +++ b/files/water/water.cg @@ -0,0 +1,56 @@ +void main_vp +( + in float4 iPos : POSITION + , in float2 iUv : TEXCOORD0 + + , out float4 oPos : POSITION + , out float3 oScreenCoords : TEXCOORD0 + , out float2 oUv : TEXCOORD1 + + , uniform float4x4 wvpMat +) +{ + oPos = mul(wvpMat, iPos); + + oUv = iUv * 10; // uv scale + + float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5, + 0, -0.5, 0, 0.5, + 0, 0, 0.5, 0.5, + 0, 0, 0, 1 ); + float4 texcoordProj = mul(scalemat, oPos); + oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); +} + +void main_fp +( + out float4 oColor : COLOR + + , in float3 iScreenCoords : TEXCOORD0 + , in float2 iUv : TEXCOORD1 + , uniform float renderTargetFlipping + + , uniform sampler2D reflectionMap : register(s0) + , uniform sampler2D normalMap : register(s1) + , uniform float time +) +{ + + float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; + screenCoords.y = (renderTargetFlipping == -1) ? (1-screenCoords.y) : screenCoords.y; + + float2 uv1 = iUv + time * float2(0.5, 0); + float2 uv2 = iUv + time * float2(0, 0.5); + float2 uv3 = iUv + time * float2(-0.5, 0); + float2 uv4 = iUv + time * float2(0, -0.5); + + float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4); + normal = normal / 4.f; + normal = 2*normal - 1; + screenCoords += normal.yx * 0.05; + + float4 reflection = tex2D(reflectionMap, screenCoords); + + oColor.xyz = reflection.xyz; + oColor.a = 0.45; +} diff --git a/files/water/water.material b/files/water/water.material index 50dfd9379..8f8f72df0 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -51,11 +51,17 @@ material Water } fragment_program_ref Water_FP { + param_named_auto time time 0.1 } texture_unit reflectionMap { texture WaterReflection + tex_address_mode clamp + } + texture_unit normalMap + { + texture WaterNormal2.tga } } } From 2fa9bac5172476893f78fdcb45d467ce10a5f0cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 22:04:37 +0200 Subject: [PATCH 023/185] added fog --- files/water/water.cg | 8 +++++++- files/water/water.material | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/files/water/water.cg b/files/water/water.cg index 6d5df987d..70d3339b1 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -6,6 +6,7 @@ void main_vp , out float4 oPos : POSITION , out float3 oScreenCoords : TEXCOORD0 , out float2 oUv : TEXCOORD1 + , out float oDepth : TEXCOORD2 , uniform float4x4 wvpMat ) @@ -13,6 +14,7 @@ void main_vp oPos = mul(wvpMat, iPos); oUv = iUv * 10; // uv scale + oDepth = oPos.z; float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5, 0, -0.5, 0, 0.5, @@ -28,11 +30,14 @@ void main_fp , in float3 iScreenCoords : TEXCOORD0 , in float2 iUv : TEXCOORD1 + , in float iDepth : TEXCOORD2 , uniform float renderTargetFlipping , uniform sampler2D reflectionMap : register(s0) , uniform sampler2D normalMap : register(s1) , uniform float time + , uniform float4 fogParams + , uniform float4 fogColour ) { @@ -51,6 +56,7 @@ void main_fp float4 reflection = tex2D(reflectionMap, screenCoords); - oColor.xyz = reflection.xyz; + float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); + oColor.xyz = lerp(reflection.xyz, fogColour, fogValue); oColor.a = 0.45; } diff --git a/files/water/water.material b/files/water/water.material index 8f8f72df0..abd5ad80e 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -52,6 +52,8 @@ material Water fragment_program_ref Water_FP { param_named_auto time time 0.1 + param_named_auto fogColour fog_colour + param_named_auto fogParams fog_params } texture_unit reflectionMap From 328bdaafb64c30981c6b1515e6a25c77a9d96823 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Apr 2012 22:53:08 +0200 Subject: [PATCH 024/185] fixed a problem with the underwater compositor --- files/settings-default.cfg | 6 ++++++ files/water/GlassFP.cg | 2 +- files/water/water.material | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ea2aa8ff1..9be18f61b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -57,3 +57,9 @@ reflect small statics = false reflect actors = true reflect misc = false + +[Render] + +# Only supported on SM3+ cards +# If you have a lower end card, this will be disabled automatically +multiple render targets = true diff --git a/files/water/GlassFP.cg b/files/water/GlassFP.cg index eb18885d2..c294f6fff 100644 --- a/files/water/GlassFP.cg +++ b/files/water/GlassFP.cg @@ -6,7 +6,7 @@ float4 main_ps(float2 iTexCoord : TEXCOORD0, float3 noiseCoord : TEXCOORD1, uniform float4 tintColour) : COLOR { - float4 normal = tex2D(NormalMap, noiseCoord); + float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; return tex2D(RT, iTexCoord + normal.xy * 0.05) + diff --git a/files/water/water.material b/files/water/water.material index abd5ad80e..bca5a9281 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -48,6 +48,7 @@ material Water vertex_program_ref Water_VP { + param_named_auto renderTargetFlipping render_target_flipping } fragment_program_ref Water_FP { From 6442d49e1630daaa9f5ef74f8dc2eaee1de68730 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Apr 2012 18:53:40 +0200 Subject: [PATCH 025/185] render queue groups, sky fix --- apps/openmw/mwrender/creatureanimation.cpp | 21 +++++++++++++++++++++ apps/openmw/mwrender/npcanimation.cpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/objects.cpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/occlusionquery.cpp | 7 ++++--- apps/openmw/mwrender/renderconst.hpp | 13 ++++++++++++- apps/openmw/mwrender/sky.cpp | 16 ++++++++-------- apps/openmw/mwrender/terrain.cpp | 1 + apps/openmw/mwrender/water.cpp | 3 ++- 8 files changed, 88 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 4c2ce8399..e0eb5ccc2 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -22,6 +22,27 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme NifOgre::NIFLoader::load(meshNumbered); base = mRend.getScene()->createEntity(meshNumbered); base->setVisibilityFlags(RV_Actors); + + bool transparent = false; + for (unsigned int i=0; igetNumSubEntities(); ++i) + { + Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } + } + } + base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + std::string meshZero = mesh + "0000>|"; if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){ diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 3a4d9300d..9de5705e3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -67,6 +67,26 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O base = mRend.getScene()->createEntity(smodel); base->setVisibilityFlags(RV_Actors); + bool transparent = false; + for (unsigned int i=0; igetNumSubEntities(); ++i) + { + Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } + } + } + base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones //stay in the same place when we skipanim, or open a gui window diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bd39e1f5a..9d743fe90 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -113,6 +113,26 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) bounds.scale(insert->getScale()); mBounds[ptr.getCell()].merge(bounds); + bool transparent = false; + for (unsigned int i=0; igetNumSubEntities(); ++i) + { + Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } + } + } + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) { insert->attachObject(ent); diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 781b522b6..ff1ce82e7 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -1,4 +1,5 @@ #include "occlusionquery.hpp" +#include "renderconst.hpp" #include #include @@ -39,8 +40,8 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod return; } - // This means that everything up to RENDER_QUEUE_MAIN can occlude the objects that are tested - const int queue = RENDER_QUEUE_MAIN+1; + // This means that everything up to RQG_Main can occlude the objects that are tested + const int queue = RQG_Main+1; MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels"); @@ -152,7 +153,7 @@ void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocati * this can happen for example if the object that is tested is outside of the view frustum * to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually */ - if (queueGroupId == RENDER_QUEUE_SKIES_LATE) + if (queueGroupId == RQG_SkiesLate) { if (mWasVisible == false && mDoQuery) { diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 5e1c6c7bb..6eba8d92e 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -7,7 +7,18 @@ namespace MWRender { // Render queue groups -/// \todo +enum RenderQueueGroups +{ + // Sky early (atmosphere, clouds, moons) + RQG_SkiesEarly = Ogre::RENDER_QUEUE_SKIES_EARLY, + + RQG_Main = Ogre::RENDER_QUEUE_MAIN, + + RQG_Alpha = Ogre::RENDER_QUEUE_7, + + // Sky late (sun & sun flare) + RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE +}; // Visibility flags enum VisibilityFlags diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8e774eb08..7ccbaf8e2 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -89,7 +89,6 @@ void BillboardObject::init(const String& textureName, /// \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_MAIN+2); mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON); mBBSet->setCommonDirection( -position.normalisedCopy() ); mBBSet->setVisibilityFlags(RV_Sky); @@ -359,15 +358,16 @@ void SkyManager::create() 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); + mSecunda->setRenderQueue(RQG_SkiesEarly+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->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode); + mSun->setRenderQueue(RQG_SkiesEarly+4); 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); + mSunGlare->setRenderQueue(RQG_SkiesLate); HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); @@ -376,7 +376,7 @@ void SkyManager::create() /// \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); + night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); mAtmosphereNight = mRootNode->createChildSceneNode(); @@ -450,7 +450,7 @@ void SkyManager::create() ModVertexAlpha(atmosphere_ent, 0); - atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY); + atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay->attachObject(atmosphere_ent); @@ -489,7 +489,7 @@ void SkyManager::create() NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif"); clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5); + clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); SceneNode* clouds_node = mRootNode->createChildSceneNode(); clouds_node->attachObject(clouds_ent); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); @@ -738,7 +738,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) strength = 1.f; mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - mSun->setVisibility(mGlareFade >= 0.5 ? weather.mGlareView * mGlareFade * strength : 0); + mSun->setVisibility(weather.mGlareView); mAtmosphereNight->setVisible(weather.mNight && mEnabled); } diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 6c11f7485..ed2c983dd 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -161,6 +161,7 @@ namespace MWRender numTextures, indexes); terrain->setVisibilityFlags(RV_Terrain); + terrain->setRenderQueueGroup(RQG_Main); if ( land && land->landData->usingColours ) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index df6d1a97a..1983616d6 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -26,10 +26,11 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mWaterPlane = Plane(Vector3::UNIT_Y, 0); - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Vector3::UNIT_Z); + MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); + mWater->setRenderQueueGroup(RQG_Alpha); mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") From 006970fd792b27d6fabb8fd52738e42eef9edc1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Apr 2012 19:53:41 +0200 Subject: [PATCH 026/185] add MRT code to shaders --- components/nifogre/ogre_nif_loader.cpp | 28 +++++++++++++++++++------- files/gbuffer/gbuffer.compositor | 0 files/gbuffer/gbuffer.material | 0 3 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 files/gbuffer/gbuffer.compositor create mode 100644 files/gbuffer/gbuffer.material diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 7fa45815f..83510db13 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -302,6 +302,8 @@ void NIFLoader::createMaterial(const String &name, if (Settings::Manager::getBool("shaders", "Objects")) { + bool mrt = Settings::Manager::getBool("multiple render targets", "Render"); + // Create shader for the material // vertex HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); @@ -324,9 +326,8 @@ void NIFLoader::createMaterial(const String &name, " out float4 oPosition : POSITION, \n" " out float4 oPositionObjSpace : TEXCOORD1, \n" " out float4 oNormal : TEXCOORD2, \n" - " out float oFogValue : TEXCOORD3, \n" + " out float oDepth : TEXCOORD3, \n" " out float4 oVertexColour : TEXCOORD4, \n" - " uniform float4 fogParams, \n" " uniform float4x4 worldViewProj \n" ") \n" "{ \n" @@ -334,13 +335,12 @@ void NIFLoader::createMaterial(const String &name, " oUV = uv; \n" " oNormal = normal; \n" " oPosition = mul( worldViewProj, position ); \n" - " oFogValue = saturate((oPosition.z - fogParams.y) * fogParams.w); \n" + " oDepth = oPosition.z; \n" " oPositionObjSpace = position; \n" "}"; vertex->setSource(outStream.str()); vertex->load(); vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - vertex->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); } else vertex = mgr.getByName("main_vp"); @@ -370,9 +370,14 @@ void NIFLoader::createMaterial(const String &name, " uniform sampler2D texture : TEXUNIT0, \n" " float4 positionObjSpace : TEXCOORD1, \n" " float4 normal : TEXCOORD2, \n" - " float fogValue : TEXCOORD3, \n" + " float iDepth : TEXCOORD3, \n" " float4 vertexColour : TEXCOORD4, \n" - " uniform float4 fogColour, \n"; + " uniform float4 fogColour, \n" + " uniform float4 fogParams, \n"; + + if (mrt) outStream << + " out float4 oColor1 : COLOR1, \n" + " uniform float far, \n"; for (int i=0; isetSource(outStream.str()); fragment->load(); @@ -425,6 +436,9 @@ void NIFLoader::createMaterial(const String &name, fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); + if (mrt) + fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); } else fragment = mgr.getByName("main_fp"); diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor new file mode 100644 index 000000000..e69de29bb diff --git a/files/gbuffer/gbuffer.material b/files/gbuffer/gbuffer.material new file mode 100644 index 000000000..e69de29bb From eb67afe5528aae8fdb288e20db5f13d2959625bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Apr 2012 20:18:08 +0200 Subject: [PATCH 027/185] added MRT output to terrain material --- apps/openmw/mwrender/terrainmaterial.cpp | 42 ++++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 922ea2280..867ec8e1f 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -557,7 +557,10 @@ namespace Ogre params->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); //params->setNamedAutoConstant("lightSpecularColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, i); } - + + if (Settings::Manager::getBool("multiple render targets", "Render")) + params->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); + params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); @@ -753,12 +756,7 @@ namespace Ogre ret->unload(); } - if(prof->isLayerNormalMappingEnabled() || prof->isLayerParallaxMappingEnabled()) - ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1"); - //else - //ret->setParameter("profiles", "ps_3_0 ps_2_0 fp30 arbfp1"); - else // fp30 doesn't work (black terrain) - ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1"); + ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1"); ret->setParameter("entry_point", "main_fp"); return ret; @@ -917,7 +915,7 @@ namespace Ogre outStream << - "float4 main_fp(\n" + "void main_fp(\n" "float4 position : TEXCOORD0,\n"; uint texCoordSet = 1; @@ -1034,8 +1032,15 @@ namespace Ogre __FUNCTION__); } + if (Settings::Manager::getBool("multiple render targets", "Render")) outStream << + " , out float4 oColor : COLOR \n" + " , out float4 oColor1 : COLOR1 \n" + " , uniform float far \n"; + else outStream << + " , out float4 oColor : COLOR \n"; + outStream << - ") : COLOR\n" + ")\n" "{\n" " float4 outputCol;\n" " float shadow = 1.0;\n" @@ -1241,6 +1246,10 @@ namespace Ogre " oPos = mul(viewProjMatrix, worldPos);\n" " oUVMisc.xy = uv.xy;\n"; + outStream << + " // pass cam depth\n" + " oUVMisc.z = oPos.z;\n"; + bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; if (fog) { @@ -1337,7 +1346,12 @@ namespace Ogre } // Final return - outStream << " return outputCol;\n" + outStream << " oColor = outputCol;\n"; + + if (Settings::Manager::getBool("multiple render targets", "Render")) outStream << + " oColor1 = float4(uvMisc.z / far, 0, 0, 1); \n"; + + outStream << "}\n"; } @@ -1511,14 +1525,6 @@ namespace Ogre } } - - if (prof->getReceiveDynamicShadowsPSSM()) - { - outStream << - " // pass cam depth\n" - " oUVMisc.z = oPos.z;\n"; - } - } //--------------------------------------------------------------------- void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsParams( From 2c7c945208789b2ea29a8755608fc212721f3462 Mon Sep 17 00:00:00 2001 From: gugus Date: Wed, 4 Apr 2012 22:13:57 +0200 Subject: [PATCH 028/185] check playerfaction during dialogue --- apps/openmw/mwdialogue/dialoguemanager.cpp | 31 ++++++++++++++++++++++ apps/openmw/mwdialogue/dialoguemanager.hpp | 3 +++ 2 files changed, 34 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 1e6faf292..cd7be5031 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -493,6 +493,21 @@ namespace MWDialogue } // TODO check player faction + if(!info.pcFaction.empty()) + { + MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + std::map::iterator it = stats.mFactionRank.find(info.npcFaction); + if(it!=stats.mFactionRank.end()) + { + //check rank + if(it->second < info.data.rank) return false; + } + else + { + //not in the faction + return false; + } + } //check gender ESMS::LiveCellRef* npc = actor.get(); @@ -655,6 +670,7 @@ namespace MWDialogue void DialogueManager::executeScript(std::string script) { + std::cout << script; std::vector code; if(compile(script,code)) { @@ -796,4 +812,19 @@ namespace MWDialogue mChoiceMap[question] = choice; mIsInChoice = true; } + + std::string DialogueManager::getFaction() + { + std::string factionID(""); + MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + if(stats.mFactionRank.empty()) + { + std::cout << "No faction for this actor!"; + } + else + { + factionID = stats.mFactionRank.begin()->first; + } + return factionID; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index 260d8e339..d0380fa71 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -63,6 +63,9 @@ namespace MWDialogue void askQuestion(std::string question,int choice); + ///get the faction of the actor you are talking with + std::string getFaction(); + //calbacks for the GUI void keywordSelected(std::string keyword); void goodbyeSelected(); From aaa5368fe927b093b239862bb7d069c83099f140 Mon Sep 17 00:00:00 2001 From: gugus Date: Wed, 4 Apr 2012 22:14:38 +0200 Subject: [PATCH 029/185] added script instruction pcraiserank. Does not work yet. --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/statsextensions.cpp | 27 ++++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7ff60a203..27b426d0e 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -127,4 +127,5 @@ op 0x2000141: GetWaterLevel op 0x2000142: SetWaterLevel op 0x2000143: ModWaterLevel op 0x2000144: ToggleWater, twa -opcodes 0x2000145-0x3ffffff unused +op 0x2000145: PCRaiseRank +opcodes 0x2000146-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 85ac54348..be31321e9 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -17,6 +17,8 @@ #include "interpretercontext.hpp" #include "ref.hpp" +#include "../mwdialogue/dialoguemanager.hpp" + namespace MWScript { namespace Stats @@ -303,12 +305,18 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + std::cout << "try to rais rank..."; MWScript::InterpreterContext& context = static_cast (runtime.getContext()); - - std::string factionID = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - context.getEnvironment().mWorld->getPlayer().raiseRank(factionID); + + std::string factionID = context.getEnvironment().mDialogueManager->getFaction(); + if(factionID != "") + { + std::cout << "raiserank!!!!!"; + MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + } + std::cout << std::endl; } }; @@ -342,8 +350,8 @@ namespace MWScript const int opcodeSetSkillExplicit = 0x20000df; const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; - const int opcodePCJoinFaction = 0x2000141; - const int opcodePCRaiseRank = 0x2000142; + //const int opcodePCJoinFaction = 0x2000141; + const int opcodePCRaiseRank = 0x2000145; void registerExtensions (Compiler::Extensions& extensions) { @@ -415,8 +423,9 @@ namespace MWScript extensions.registerInstruction (mod + skills[i], "l", opcodeModSkill+i, opcodeModSkillExplicit+i); } - extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); - extensions.registerInstruction("PCRaiseRank","S",opcodePCRaiseRank); + //extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); + std::cout << "rgister raiserank"; + extensions.registerInstruction("pcraiserank","",opcodePCRaiseRank); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -473,7 +482,7 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } - interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); + //interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment5(opcodePCRaiseRank,new OpPCRaiseRank); } } From 3f05aba76dc3d6a6c8747ee453c328cf833b7376 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 01:21:36 +0200 Subject: [PATCH 030/185] got MRT working, some minor quirks to solve (black viewport background) --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/occlusionquery.cpp | 9 +-- apps/openmw/mwrender/renderconst.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 19 ++++++ apps/openmw/mwrender/water.cpp | 15 +++++ files/CMakeLists.txt | 4 ++ files/gbuffer/gbuffer.compositor | 81 +++++++++++++++++++++++ files/gbuffer/gbuffer.material | 63 ++++++++++++++++++ files/water/GlassFP.cg | 6 +- files/water/water.cg | 12 ++-- files/water/water.material | 8 ++- 11 files changed, 206 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cfcf9f76b..a6b712abf 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -357,6 +357,7 @@ void OMW::Engine::go() addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); + addResourcesDirectory(mResDir / "gbuffer"); // Create the window mOgre->createWindow("OpenMW"); diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index ff1ce82e7..5be7202b3 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -40,9 +40,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod return; } - // This means that everything up to RQG_Main can occlude the objects that are tested - const int queue = RQG_Main+1; - MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels"); matQueryArea->setDepthWriteEnabled(false); @@ -65,14 +62,14 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryTotal->setDefaultDimensions(150, 150); mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->setMaterialName("QueryTotalPixels"); - mBBQueryTotal->setRenderQueueGroup(queue+1); + mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); mBBNodeReal->attachObject(mBBQueryTotal); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); mBBQueryVisible->setDefaultDimensions(150, 150); mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->setMaterialName("QueryVisiblePixels"); - mBBQueryVisible->setRenderQueueGroup(queue+1); + mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); mBBNodeReal->attachObject(mBBQueryVisible); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); @@ -80,7 +77,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); - mBBQuerySingleObject->setRenderQueueGroup(queue); + mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); mObjectNode->attachObject(mBBQuerySingleObject); mRendering->getScene()->addRenderObjectListener(this); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 6eba8d92e..113024ace 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -14,6 +14,8 @@ enum RenderQueueGroups RQG_Main = Ogre::RENDER_QUEUE_MAIN, + RQG_OcclusionQuery = Ogre::RENDER_QUEUE_MAIN+1, + RQG_Alpha = Ogre::RENDER_QUEUE_7, // Sky late (sun & sun flare) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 98344297f..7797d1852 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -37,6 +37,14 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + if (Settings::Manager::getBool("multiple render targets", "Render")) + { + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer"); + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); + } + // Turn the entire scene (represented by the 'root' node) -90 // degrees around the x axis. This makes Z go upwards, and Y go into // the screen (when x is to the right.) This is the orientation that @@ -252,11 +260,22 @@ bool RenderingManager::toggleRenderMode(int mode) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { + // disable compositors + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false); + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false); + mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); return true; } else { + // re-enable compositors + if (Settings::Manager::getBool("multiple render targets", "Render")) + { + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); + } + mRendering.getCamera()->setPolygonMode(PM_SOLID); return false; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1983616d6..b3db66189 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -181,6 +181,21 @@ Ogre::MaterialPtr Water::createMaterial() if (mReflectionTarget == 0) mat->removeTechnique(0); + if (Settings::Manager::getBool("multiple render targets", "Render")) + { + CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); + + TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); + TextureUnitState* tus = mat->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); + if (tus != 0) + tus->setTexture(colorTexture); + + TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); + tus = mat->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap"); + if (tus != 0) + tus->setTexture(depthTexture); + } + return mat; } diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 56c3db862..377e2d1f8 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -8,3 +8,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINA configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal2.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal2.tga" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/resources/water/water.cg" COPYONLY) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY) diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index e69de29bb..d51d3700c 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -0,0 +1,81 @@ +// Compositor that just controls output to the MRT textures +compositor gbuffer +{ + technique + { + // MRT output. Currently this is a color texture plus a depth texture + texture mrt_output target_width target_height PF_FLOAT16_RGBA PF_FLOAT16_RGBA chain_scope depth_pool 2 + + target mrt_output + { + input none + pass clear + { + } + pass render_scene + { + first_render_queue 0 + last_render_queue 69 + } + + } + + target_output + { + input none + + pass render_quad + { + material RenderScene + input 0 mrt_output 0 + } + } + } +} + +// Finalizer compositor to render objects that we don't want in the MRT textures (this is the case for most transparent stuff) +compositor gbufferFinalizer +{ + technique + { + texture no_mrt_output target_width target_height PF_R8G8B8A8 depth_pool 2 no_fsaa + texture previousscene target_width target_height PF_R8G8B8A8 + + target previousscene + { + input previous + } + target no_mrt_output + { + input none + shadows off + pass clear + { + buffers colour + colour_value 0 0 0 0 + } + pass render_quad + { + material RenderSceneNoDepth + input 0 previousscene + } + pass render_scene + { + first_render_queue 70 + last_render_queue 100 + } + } + target_output + { + input none + pass clear + { + } + pass render_quad + { + material RenderSceneNoDepth + input 0 no_mrt_output + } + } + } +} diff --git a/files/gbuffer/gbuffer.material b/files/gbuffer/gbuffer.material index e69de29bb..faa8dd498 100644 --- a/files/gbuffer/gbuffer.material +++ b/files/gbuffer/gbuffer.material @@ -0,0 +1,63 @@ +vertex_program RenderGBuffer_vs cg +{ + source gbuffer.cg + profiles vs_4_0 vs_1_1 arbvp1 + entry_point RenderScene_vs + default_params + { + param_named_auto wvp worldviewproj_matrix + } +} +fragment_program RenderGBuffer_ps cg +{ + source gbuffer.cg + entry_point RenderScene_ps + profiles ps_4_0 ps_2_x arbfp1 + default_params + { + } +} +material RenderScene +{ + technique + { + pass + { + vertex_program_ref RenderGBuffer_vs + { + } + + fragment_program_ref RenderGBuffer_ps + { + } + + texture_unit tex1 + { + //scenebuffer + } + } + } +} + +material RenderSceneNoDepth +{ + technique + { + pass + { + depth_write off + vertex_program_ref RenderGBuffer_vs + { + } + + fragment_program_ref RenderGBuffer_ps + { + } + + texture_unit tex1 + { + //scenebuffer + } + } + } +} diff --git a/files/water/GlassFP.cg b/files/water/GlassFP.cg index c294f6fff..0ce343b0a 100644 --- a/files/water/GlassFP.cg +++ b/files/water/GlassFP.cg @@ -1,9 +1,9 @@ -sampler RT : register(s0); -sampler NormalMap : register(s1); -sampler CausticMap : register(s2); float4 main_ps(float2 iTexCoord : TEXCOORD0, float3 noiseCoord : TEXCOORD1, + uniform sampler2D RT : register(s0), + uniform sampler2D NormalMap : register(s1), + uniform sampler2D CausticMap : register(s2), uniform float4 tintColour) : COLOR { float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; diff --git a/files/water/water.cg b/files/water/water.cg index 70d3339b1..88515c3e8 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -34,7 +34,8 @@ void main_fp , uniform float renderTargetFlipping , uniform sampler2D reflectionMap : register(s0) - , uniform sampler2D normalMap : register(s1) + , uniform sampler2D refractionMap : register(s1) + , uniform sampler2D normalMap : register(s2) , uniform float time , uniform float4 fogParams , uniform float4 fogColour @@ -42,7 +43,7 @@ void main_fp { float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; - screenCoords.y = (renderTargetFlipping == -1) ? (1-screenCoords.y) : screenCoords.y; + screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; float2 uv1 = iUv + time * float2(0.5, 0); float2 uv2 = iUv + time * float2(0, 0.5); @@ -55,8 +56,11 @@ void main_fp screenCoords += normal.yx * 0.05; float4 reflection = tex2D(reflectionMap, screenCoords); + float4 refraction = tex2D(refractionMap, screenCoords); + + oColor.xyz = lerp(reflection.xyz, refraction.xyz, 1); float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); - oColor.xyz = lerp(reflection.xyz, fogColour, fogValue); - oColor.a = 0.45; + oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); + oColor.a = 1; } diff --git a/files/water/water.material b/files/water/water.material index bca5a9281..c964e9ae4 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -48,13 +48,13 @@ material Water vertex_program_ref Water_VP { - param_named_auto renderTargetFlipping render_target_flipping } fragment_program_ref Water_FP { param_named_auto time time 0.1 param_named_auto fogColour fog_colour param_named_auto fogParams fog_params + param_named_auto renderTargetFlipping render_target_flipping } texture_unit reflectionMap @@ -62,6 +62,12 @@ material Water texture WaterReflection tex_address_mode clamp } + + texture_unit refractionMap + { + tex_address_mode clamp + } + texture_unit normalMap { texture WaterNormal2.tga From ca4de0606ea0a4b57b8b718229768d33019cd7e5 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Wed, 4 Apr 2012 23:23:24 -0400 Subject: [PATCH 031/185] Some planning --- apps/openmw/mwrender/npcanimation.hpp | 34 ++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e2071957c..e524878cc 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,7 +15,39 @@ namespace MWRender{ class NpcAnimation: public Animation{ - +private: + + int mStateID; + //Free Parts + Ogre::Entity* chest; std::vector* chestShapes; + Ogre::Entity* skirt; std::vector* skirtShapes; + Ogre::Entity* rhand; std::vector* rhandShapes; + Ogre::Entity* lhand; std::vector* lhandShapes; + Ogre::Entity* tail; std::vector* tailShapes; + Ogre::Entity* lBeastFoot; std::vector* lBeastFootShapes; + Ogre::Entity* rBeastFoot; std::vector* rBeastFootShapes; + + //Bounded Parts + Ogre::Entity* lclavicle; + Ogre::Entity* rclavicle; + Ogre::Entity* rupperArm; + Ogre::Entity* lupperArm; + Ogre::Entity* rUpperLeg; + Ogre::Entity* lUpperLeg; + Ogre::Entity* lForearm; + Ogre::Entity* rForearm; + Ogre::Entity* lWrist; + Ogre::Entity* rWrist; + Ogre::Entity* rKnee; + Ogre::Entity* lKnee; + Ogre::Entity* neck; + Ogre::Entity* rAnkle; + Ogre::Entity* lAnkle; + Ogre::Entity* groin; + Ogre::Entity* lfoot; + Ogre::Entity* rfoot; + Ogre::Entity* hair; + Ogre::Entity* head; public: From ab8b74dcac00af9684cdc0d8d1d2b0fcee184dd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 08:58:21 +0200 Subject: [PATCH 032/185] forgot adding a file --- apps/openmw/mwrender/water.cpp | 2 +- files/gbuffer/gbuffer.cg | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 files/gbuffer/gbuffer.cg diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b3db66189..1caced9f5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -183,7 +183,7 @@ Ogre::MaterialPtr Water::createMaterial() if (Settings::Manager::getBool("multiple render targets", "Render")) { - CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); + CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); TextureUnitState* tus = mat->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); diff --git a/files/gbuffer/gbuffer.cg b/files/gbuffer/gbuffer.cg new file mode 100644 index 000000000..c7f2fe678 --- /dev/null +++ b/files/gbuffer/gbuffer.cg @@ -0,0 +1,18 @@ +void RenderScene_vs(in float4 position : POSITION + ,in float2 uv :TEXCOORD0 + ,uniform float4x4 wvp + ,out float4 oPosition : POSITION + ,out float2 oUV :TEXCOORD0) +{ + oPosition = mul(wvp, position); + oUV = uv; +} + +void RenderScene_ps(in float4 position : POSITION + ,in float2 uv :TEXCOORD0 + ,uniform sampler2D tex1 : TEXUNIT0 + ,out float4 oColor : COLOR) +{ + float4 scene =tex2D(tex1, uv); + oColor= scene; +} From 36fd9b9f263c7c4f4fc9df759253b96785121cdf Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 10:39:22 +0200 Subject: [PATCH 033/185] shore transition test --- files/water/water.cg | 17 ++++++++++++----- files/water/water.material | 6 ++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/files/water/water.cg b/files/water/water.cg index 88515c3e8..c8156d9ce 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -35,8 +35,10 @@ void main_fp , uniform sampler2D reflectionMap : register(s0) , uniform sampler2D refractionMap : register(s1) - , uniform sampler2D normalMap : register(s2) + , uniform sampler2D depthMap : register(s2) + , uniform sampler2D normalMap : register(s3) , uniform float time + , uniform float far , uniform float4 fogParams , uniform float4 fogColour ) @@ -45,6 +47,9 @@ void main_fp float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; + float depth1 = tex2D(depthMap, screenCoords).r * far - iDepth; + depth1 = saturate(depth1 / 500.f); + float2 uv1 = iUv + time * float2(0.5, 0); float2 uv2 = iUv + time * float2(0, 0.5); float2 uv3 = iUv + time * float2(-0.5, 0); @@ -53,12 +58,14 @@ void main_fp float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4); normal = normal / 4.f; normal = 2*normal - 1; - screenCoords += normal.yx * 0.05; - float4 reflection = tex2D(reflectionMap, screenCoords); - float4 refraction = tex2D(refractionMap, screenCoords); + float2 screenCoords_reflect = screenCoords + normal.yx * 0.05; + float2 screenCoords_refract = screenCoords + normal.yx * 0.1 * depth1; + + float4 reflection = tex2D(reflectionMap, screenCoords_reflect); + float4 refraction = tex2D(refractionMap, screenCoords_refract); - oColor.xyz = lerp(reflection.xyz, refraction.xyz, 1); + oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1); float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); diff --git a/files/water/water.material b/files/water/water.material index c964e9ae4..dd01af405 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -55,6 +55,7 @@ material Water param_named_auto fogColour fog_colour param_named_auto fogParams fog_params param_named_auto renderTargetFlipping render_target_flipping + param_named_auto far far_clip_distance } texture_unit reflectionMap @@ -68,6 +69,11 @@ material Water tex_address_mode clamp } + texture_unit depthMap + { + tex_address_mode clamp + } + texture_unit normalMap { texture WaterNormal2.tga From 8ddc8131a5480d0b134bb90d5cd0c9283957937d Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 11:18:58 +0200 Subject: [PATCH 034/185] fresnel test --- files/gbuffer/gbuffer.compositor | 1 + files/water/water.cg | 13 ++++++++++++- files/water/water.material | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index d51d3700c..a81ad18c3 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -11,6 +11,7 @@ compositor gbuffer input none pass clear { + colour_value 0 0 0 1 } pass render_scene { diff --git a/files/water/water.cg b/files/water/water.cg index c8156d9ce..bd18286bc 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -7,8 +7,10 @@ void main_vp , out float3 oScreenCoords : TEXCOORD0 , out float2 oUv : TEXCOORD1 , out float oDepth : TEXCOORD2 + , out float4 oEyeVector : TEXCOORD3 , uniform float4x4 wvpMat + , uniform float4 camPosObjSpace ) { oPos = mul(wvpMat, iPos); @@ -22,6 +24,8 @@ void main_vp 0, 0, 0, 1 ); float4 texcoordProj = mul(scalemat, oPos); oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + oEyeVector = camPosObjSpace - iPos; } void main_fp @@ -31,6 +35,7 @@ void main_fp , in float3 iScreenCoords : TEXCOORD0 , in float2 iUv : TEXCOORD1 , in float iDepth : TEXCOORD2 + , in float4 iEyeVector : TEXCOORD3 , uniform float renderTargetFlipping , uniform sampler2D reflectionMap : register(s0) @@ -47,17 +52,19 @@ void main_fp float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; + // Sample screen-space depth map and subtract pixel depth to get the real water depth float depth1 = tex2D(depthMap, screenCoords).r * far - iDepth; depth1 = saturate(depth1 / 500.f); + // Simple wave effect. to be replaced by something better float2 uv1 = iUv + time * float2(0.5, 0); float2 uv2 = iUv + time * float2(0, 0.5); float2 uv3 = iUv + time * float2(-0.5, 0); float2 uv4 = iUv + time * float2(0, -0.5); - float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4); normal = normal / 4.f; normal = 2*normal - 1; + //normal = normalize(normal); float2 screenCoords_reflect = screenCoords + normal.yx * 0.05; float2 screenCoords_refract = screenCoords + normal.yx * 0.1 * depth1; @@ -65,6 +72,10 @@ void main_fp float4 reflection = tex2D(reflectionMap, screenCoords_reflect); float4 refraction = tex2D(refractionMap, screenCoords_refract); + // fresnel + //float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0); + //float reflectionFactor = saturate(0.3 + 0.7 * pow(facing, 2)); + oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1); float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); diff --git a/files/water/water.material b/files/water/water.material index dd01af405..ffd813e16 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -48,6 +48,7 @@ material Water vertex_program_ref Water_VP { + //param_named_auto camPosObjSpace camera_position_object_space } fragment_program_ref Water_FP { From 5664d879a5c0b37c1228849854188cc834c81105 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 11:40:56 +0200 Subject: [PATCH 035/185] fixed some sky objects --- apps/openmw/mwrender/sky.cpp | 82 ++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7ccbaf8e2..3f815d9fc 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -109,6 +109,59 @@ void BillboardObject::init(const String& textureName, p->createTextureUnitState(textureName); mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); + HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); + HighLevelGpuProgramPtr vshader; + if (mgr.resourceExists("BBO_VP")) + vshader = mgr.getByName("BBO_VP"); + else + vshader = mgr.createProgram("BBO_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("BBO_FP")) + fshader = mgr.getByName("BBO_FP"); + else + fshader = mgr.createProgram("BBO_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) * tex * 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()); + bodyCount++; } @@ -469,21 +522,42 @@ void SkyManager::create() " float4 position : POSITION, \n" " in float4 color : COLOR, \n" " out float4 oPosition : POSITION, \n" - " out float4 oColor : COLOR, \n" + " out float4 oVertexColor : TEXCOORD0, \n" " uniform float4 emissive, \n" " uniform float4x4 worldViewProj \n" ") \n" "{ \n" " oPosition = mul( worldViewProj, position ); \n" - " oColor = color * emissive; \n" + " oVertexColor = color; \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()); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(""); + + HighLevelGpuProgramPtr fshader = mgr.createProgram("Atmosphere_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 _outStream; + _outStream << + "void main_fp( \n" + " in float4 iVertexColor : TEXCOORD0, \n" + " out float4 oColor : COLOR, \n" + " uniform float4 emissive, \n" + " uniform float4x4 worldViewProj \n" + ") \n" + "{ \n" + " oColor = iVertexColor * emissive; \n" + "}"; + fshader->setSource(_outStream.str()); + fshader->load(); + + fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); // Clouds NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); From f6342cfd60ae508bd54b247a3f1ef7c5db1f8f35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 11:52:06 +0200 Subject: [PATCH 036/185] fixed viewport background color, fixed indentation of some old functions --- apps/openmw/mwrender/renderingmanager.cpp | 76 ++++++++++++----------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7797d1852..ce4dea74d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -284,23 +284,27 @@ bool RenderingManager::toggleRenderMode(int mode) void RenderingManager::configureFog(ESMS::CellStore &mCell) { - Ogre::ColourValue color; - color.setAsABGR (mCell.cell->ambi.fog); + Ogre::ColourValue color; + color.setAsABGR (mCell.cell->ambi.fog); - configureFog(mCell.cell->ambi.fogDensity, color); + configureFog(mCell.cell->ambi.fogDensity, color); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { - float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); + float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); - float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); + float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); + float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); + mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); - mRendering.getCamera()->setFarClipDistance ( max / density ); - mRendering.getViewport()->setBackgroundColour (colour); + mRendering.getCamera()->setFarClipDistance ( max / density ); + mRendering.getViewport()->setBackgroundColour (colour); + + CompositorInstance* inst = CompositorManager::getSingleton().getCompositorChain(mRendering.getViewport())->getCompositor("gbuffer"); + if (inst != 0) + inst->getCompositor()->getTechnique(0)->getTargetPass(0)->getPass(0)->setClearColour(colour); } @@ -327,41 +331,43 @@ void RenderingManager::setAmbientMode() void RenderingManager::configureAmbient(ESMS::CellStore &mCell) { - mAmbientColor.setAsABGR (mCell.cell->ambi.ambient); - setAmbientMode(); + mAmbientColor.setAsABGR (mCell.cell->ambi.ambient); + setAmbientMode(); - // Create a "sun" that shines light downwards. It doesn't look - // completely right, but leave it for now. - if(!mSun) - { - mSun = mRendering.getScene()->createLight(); - } - Ogre::ColourValue colour; - colour.setAsABGR (mCell.cell->ambi.sunlight); - mSun->setDiffuseColour (colour); - mSun->setType(Ogre::Light::LT_DIRECTIONAL); - mSun->setDirection(0,-1,0); + // Create a "sun" that shines light downwards. It doesn't look + // completely right, but leave it for now. + if(!mSun) + { + mSun = mRendering.getScene()->createLight(); + } + Ogre::ColourValue colour; + colour.setAsABGR (mCell.cell->ambi.sunlight); + mSun->setDiffuseColour (colour); + mSun->setType(Ogre::Light::LT_DIRECTIONAL); + mSun->setDirection(0,-1,0); } // Switch through lighting modes. void RenderingManager::toggleLight() { - if (mAmbientMode==2) - mAmbientMode = 0; - else - ++mAmbientMode; + if (mAmbientMode==2) + mAmbientMode = 0; + else + ++mAmbientMode; - switch (mAmbientMode) - { - case 0: std::cout << "Setting lights to normal\n"; break; - case 1: std::cout << "Turning the lights up\n"; break; - case 2: std::cout << "Turning the lights to full\n"; break; - } + switch (mAmbientMode) + { + case 0: std::cout << "Setting lights to normal\n"; break; + case 1: std::cout << "Turning the lights up\n"; break; + case 2: std::cout << "Turning the lights to full\n"; break; + } - setAmbientMode(); + setAmbientMode(); } -void RenderingManager::checkUnderwater(){ - if(mWater){ +void RenderingManager::checkUnderwater() +{ + if(mWater) + { mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y ); } } From add4ebe4458fa57e8584bc3db1901a12bb1b2c0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 12:59:56 +0200 Subject: [PATCH 037/185] fresnel effect --- files/gbuffer/gbuffer.compositor | 1 + files/water/water.cg | 10 ++++++---- files/water/water.material | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index a81ad18c3..fb12b8bf4 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -11,6 +11,7 @@ compositor gbuffer input none pass clear { + // make sure to set this to the viewport background color from outside colour_value 0 0 0 1 } pass render_scene diff --git a/files/water/water.cg b/files/water/water.cg index bd18286bc..10b42eec0 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -64,7 +64,6 @@ void main_fp float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4); normal = normal / 4.f; normal = 2*normal - 1; - //normal = normalize(normal); float2 screenCoords_reflect = screenCoords + normal.yx * 0.05; float2 screenCoords_refract = screenCoords + normal.yx * 0.1 * depth1; @@ -72,11 +71,14 @@ void main_fp float4 reflection = tex2D(reflectionMap, screenCoords_reflect); float4 refraction = tex2D(refractionMap, screenCoords_refract); + // tangent to object space + normal.xyz = normal.xzy; + // fresnel - //float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0); - //float reflectionFactor = saturate(0.3 + 0.7 * pow(facing, 2)); + float facing = 1.0 - max(abs(dot(normalize(iEyeVector.xyz), normal.xyz)), 0); + float reflectionFactor = saturate(0.3 + 0.7 * pow(facing, 2)); - oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1); + oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1 * reflectionFactor); float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); diff --git a/files/water/water.material b/files/water/water.material index ffd813e16..95a0aef78 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -48,7 +48,7 @@ material Water vertex_program_ref Water_VP { - //param_named_auto camPosObjSpace camera_position_object_space + param_named_auto camPosObjSpace camera_position_object_space } fragment_program_ref Water_FP { From f49131e1b8a2c8a1976c643b77eb76f56b4bcb42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 13:09:59 +0200 Subject: [PATCH 038/185] renamed setting, automatically disable MRT when unsupported --- apps/openmw/mwrender/renderingmanager.cpp | 6 ++++++ apps/openmw/mwrender/water.cpp | 2 +- files/settings-default.cfg | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ce4dea74d..97312b697 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -37,6 +37,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + // disable MRT if it is unsupported + const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); + if (caps->getNumMultiRenderTargets() < 2 + || (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_3_0"))) + Settings::Manager::setBool("multiple render targets", "Render", false); + if (Settings::Manager::getBool("multiple render targets", "Render")) { CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1caced9f5..7e9dd957b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -52,7 +52,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); - if (Settings::Manager::getBool("reflection", "Water")) + if (Settings::Manager::getBool("shader", "Water") && Settings::Manager::getBool("multiple render targets", "Render")) { TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9be18f61b..7791f39ab 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -44,7 +44,7 @@ num lights = 8 [Water] -reflection = false +shader = false rtt size = 256 From 43fd0352f44fe8a1d6044573af18c24b2aa51a80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 14:21:57 +0200 Subject: [PATCH 039/185] removed unneeded lines --- apps/openmw/mwrender/sky.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3f815d9fc..89c1f3c09 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -523,7 +523,6 @@ void SkyManager::create() " in float4 color : COLOR, \n" " out float4 oPosition : POSITION, \n" " out float4 oVertexColor : TEXCOORD0, \n" - " uniform float4 emissive, \n" " uniform float4x4 worldViewProj \n" ") \n" "{ \n" @@ -548,7 +547,6 @@ void SkyManager::create() " in float4 iVertexColor : TEXCOORD0, \n" " out float4 oColor : COLOR, \n" " uniform float4 emissive, \n" - " uniform float4x4 worldViewProj \n" ") \n" "{ \n" " oColor = iVertexColor * emissive; \n" From e1bde415f5bf775c953cd6b551423c37420b634f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 14:22:44 +0200 Subject: [PATCH 040/185] typo --- apps/openmw/mwrender/sky.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 89c1f3c09..02af314a8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -546,7 +546,7 @@ void SkyManager::create() "void main_fp( \n" " in float4 iVertexColor : TEXCOORD0, \n" " out float4 oColor : COLOR, \n" - " uniform float4 emissive, \n" + " uniform float4 emissive \n" ") \n" "{ \n" " oColor = iVertexColor * emissive; \n" From 1b89a9e203f95427b3989ca3d5d4f30b5e064fd4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 15:30:55 +0200 Subject: [PATCH 041/185] various fixes --- apps/openmw/mwrender/renderingmanager.cpp | 9 +++--- apps/openmw/mwrender/sky.cpp | 10 +++++++ apps/openmw/mwrender/sky.hpp | 3 ++ apps/openmw/mwrender/water.cpp | 34 +++++++++++++++-------- apps/openmw/mwrender/water.hpp | 2 ++ files/water/water.cg | 2 +- 6 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 97312b697..c2ad2a043 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -27,6 +27,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mTerrainManager = new TerrainManager(mRendering.getScene(), environment); + mWater = 0; + //The fog type must be set before any terrain objects are created as if the //fog type is set to FOG_NONE then the initially created terrain won't have any fog configureFog(1, ColourValue(1,1,1)); @@ -39,8 +41,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // disable MRT if it is unsupported const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2 - || (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_3_0"))) + if (caps->getNumMultiRenderTargets() < 2) Settings::Manager::setBool("multiple render targets", "Render", false); if (Settings::Manager::getBool("multiple render targets", "Render")) @@ -73,8 +74,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - mWater = 0; - mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; @@ -311,6 +310,8 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue CompositorInstance* inst = CompositorManager::getSingleton().getCompositorChain(mRendering.getViewport())->getCompositor("gbuffer"); if (inst != 0) inst->getCompositor()->getTechnique(0)->getTargetPass(0)->getPass(0)->setClearColour(colour); + if (mWater) + mWater->setViewportBackground(colour); } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 02af314a8..43ef31d86 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -913,3 +913,13 @@ Ogre::SceneNode* SkyManager::getSunNode() if (!mCreated) return 0; return mSun->getNode(); } + +void SkyManager::setSkyPosition(const Ogre::Vector3& position) +{ + mRootNode->_setDerivedPosition(position); +} + +void SkyManager::resetSkyPosition() +{ + mRootNode->setPosition(0,0,0); +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index baf5933cb..c18b9f484 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -168,6 +168,9 @@ namespace MWRender void setGlare(const float glare); Ogre::Vector3 getRealSunPos(); + void setSkyPosition(const Ogre::Vector3& position); + void resetSkyPosition(); + private: bool mCreated; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7e9dd957b..cce25d1e9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -36,8 +36,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") + RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water") + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Misc * Settings::Manager::getBool("reflect misc", "Water"); - //+ RV_Sky; + + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + + RV_Sky; mReflectDistance = Settings::Manager::getInt("reflect distance", "Water"); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); @@ -145,11 +145,14 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) if (mReflectDistance != 0) mCamera->setFarClipDistance(mReflectDistance); - if (evt.source == mReflectionTarget) - { - mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); - mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); - } + if (evt.source == mReflectionTarget) + { + Vector3 pos = mCamera->getRealPosition(); + pos.y = mTop*2 - pos.y; + mSky->setSkyPosition(pos); + mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); + mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); + } } void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) @@ -158,11 +161,12 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) mCamera->setFarClipDistance(mOldCameraFarClip); - if (evt.source == mReflectionTarget) - { - mCamera->disableReflection(); - mCamera->disableCustomNearClipPlane(); - } + if (evt.source == mReflectionTarget) + { + mSky->resetSkyPosition(); + mCamera->disableReflection(); + mCamera->disableCustomNearClipPlane(); + } } Ogre::MaterialPtr Water::createMaterial() @@ -199,4 +203,10 @@ Ogre::MaterialPtr Water::createMaterial() return mat; } +void Water::setViewportBackground(const ColourValue& bg) +{ + if (mReflectionTarget) + mReflectionTarget->getViewport(0)->setBackgroundColour(bg); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 8e9014833..964a8c735 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -50,6 +50,8 @@ namespace MWRender { void toggle(); + void setViewportBackground(const Ogre::ColourValue& bg); + void checkUnderwater(float y); void changeCell(const ESM::Cell* cell); void setHeight(const float height); diff --git a/files/water/water.cg b/files/water/water.cg index 10b42eec0..188c37709 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -76,7 +76,7 @@ void main_fp // fresnel float facing = 1.0 - max(abs(dot(normalize(iEyeVector.xyz), normal.xyz)), 0); - float reflectionFactor = saturate(0.3 + 0.7 * pow(facing, 2)); + float reflectionFactor = saturate(0.35 + 0.65 * pow(facing, 2)); oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1 * reflectionFactor); From b8a470efcdf4b592dae3cf02f9cc211059ca0018 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 19:07:21 +0200 Subject: [PATCH 042/185] put transparent objects in a seperate render queue, in order to not mess up the mrt textures --- apps/openmw/mwrender/objects.cpp | 31 +++++++++++++++++++++++++--- apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderconst.hpp | 4 +++- apps/openmw/mwrender/water.cpp | 2 +- files/gbuffer/gbuffer.compositor | 4 ++-- files/water/water.material | 3 --- 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9d743fe90..a388d3163 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -131,7 +131,6 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) } } } - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) { @@ -139,12 +138,24 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } else { Ogre::StaticGeometry* sg = 0; - if (small) + if (transparent) + { + if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end()) + { + uniqueID = uniqueID +1; + sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); + mStaticGeometryAlpha[ptr.getCell()] = sg; + } + else + sg = mStaticGeometryAlpha[ptr.getCell()]; + } + else if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { @@ -152,7 +163,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); mStaticGeometrySmall[ptr.getCell()] = sg; - sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); /// \todo config value + sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); } else sg = mStaticGeometrySmall[ptr.getCell()]; @@ -182,6 +193,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); + sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + mRenderer.getScene()->destroyEntity(ent); } } @@ -275,6 +288,13 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; } + if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end()) + { + Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store]; + mStaticGeometryAlpha.erase(store); + mRenderer.getScene()->destroyStaticGeometry (sg); + sg = 0; + } if(mBounds.find(store) != mBounds.end()) mBounds.erase(store); @@ -292,6 +312,11 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell) Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; sg->build(); } + if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end()) + { + Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell]; + sg->build(); + } } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 5911aa4cc..4326ce326 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -15,6 +15,7 @@ class Objects{ std::map mCellSceneNodes; std::map mStaticGeometry; std::map mStaticGeometrySmall; + std::map mStaticGeometryAlpha; std::map mBounds; std::vector mLights; Ogre::SceneNode* mMwRoot; diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 113024ace..26d56a75c 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -14,10 +14,12 @@ enum RenderQueueGroups RQG_Main = Ogre::RENDER_QUEUE_MAIN, - RQG_OcclusionQuery = Ogre::RENDER_QUEUE_MAIN+1, + RQG_Water = Ogre::RENDER_QUEUE_6, RQG_Alpha = Ogre::RENDER_QUEUE_7, + RQG_OcclusionQuery = Ogre::RENDER_QUEUE_8, + // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cce25d1e9..d4ec9aeea 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -30,7 +30,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); - mWater->setRenderQueueGroup(RQG_Alpha); + mWater->setRenderQueueGroup(RQG_Water); mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index fb12b8bf4..8ab5665dd 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -17,7 +17,7 @@ compositor gbuffer pass render_scene { first_render_queue 0 - last_render_queue 69 + last_render_queue 59 } } @@ -63,7 +63,7 @@ compositor gbufferFinalizer } pass render_scene { - first_render_queue 70 + first_render_queue 60 last_render_queue 100 } } diff --git a/files/water/water.material b/files/water/water.material index 95a0aef78..f21f929d4 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -43,9 +43,6 @@ material Water { pass { - scene_blend alpha_blend - depth_write off - vertex_program_ref Water_VP { param_named_auto camPosObjSpace camera_position_object_space From 622fb568cf82526874b71d8dea15bbe38b88fc28 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 19:27:54 +0200 Subject: [PATCH 043/185] removed MRT setting and figure it out automatically --- apps/openmw/mwrender/renderingmanager.cpp | 20 ++++++++++++++------ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwrender/terrainmaterial.cpp | 7 ++++--- apps/openmw/mwrender/water.cpp | 4 ++-- components/nifogre/ogre_nif_loader.cpp | 2 +- files/settings-default.cfg | 6 ------ 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c2ad2a043..024c10f3d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -39,12 +39,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - // disable MRT if it is unsupported + // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); if (caps->getNumMultiRenderTargets() < 2) - Settings::Manager::setBool("multiple render targets", "Render", false); + Settings::Manager::setBool("shader", "Water", false); - if (Settings::Manager::getBool("multiple render targets", "Render")) + if (useMRT()) { CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); @@ -266,8 +266,11 @@ bool RenderingManager::toggleRenderMode(int mode) if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { // disable compositors - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false); + if (useMRT()) + { + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false); + CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false); + } mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); return true; @@ -275,7 +278,7 @@ bool RenderingManager::toggleRenderMode(int mode) else { // re-enable compositors - if (Settings::Manager::getBool("multiple render targets", "Render")) + if (useMRT()) { CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); @@ -449,4 +452,9 @@ void RenderingManager::enableLights() mObjects.enableLights(); } +const bool RenderingManager::useMRT() +{ + return Settings::Manager::getBool("shader", "Water"); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 27cd67bbc..da9c55cb5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -81,6 +81,8 @@ class RenderingManager: private RenderingInterface { void removeWater(); + static const bool useMRT(); + void preCellChange (MWWorld::Ptr::CellStore* store); ///< this event is fired immediately before changing cell diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 867ec8e1f..87798006c 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -37,6 +37,7 @@ THE SOFTWARE. #include "OgreShadowCameraSetupPSSM.h" #include +#include "renderingmanager.hpp" namespace Ogre { @@ -558,7 +559,7 @@ namespace Ogre //params->setNamedAutoConstant("lightSpecularColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, i); } - if (Settings::Manager::getBool("multiple render targets", "Render")) + if (MWRender::RenderingManager::useMRT()) params->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); @@ -1032,7 +1033,7 @@ namespace Ogre __FUNCTION__); } - if (Settings::Manager::getBool("multiple render targets", "Render")) outStream << + if (MWRender::RenderingManager::useMRT()) outStream << " , out float4 oColor : COLOR \n" " , out float4 oColor1 : COLOR1 \n" " , uniform float far \n"; @@ -1348,7 +1349,7 @@ namespace Ogre // Final return outStream << " oColor = outputCol;\n"; - if (Settings::Manager::getBool("multiple render targets", "Render")) outStream << + if (MWRender::RenderingManager::useMRT()) outStream << " oColor1 = float4(uvMisc.z / far, 0, 0, 1); \n"; outStream diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index d4ec9aeea..cbce0d075 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -52,7 +52,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); - if (Settings::Manager::getBool("shader", "Water") && Settings::Manager::getBool("multiple render targets", "Render")) + if (Settings::Manager::getBool("shader", "Water")) { TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); @@ -185,7 +185,7 @@ Ogre::MaterialPtr Water::createMaterial() if (mReflectionTarget == 0) mat->removeTechnique(0); - if (Settings::Manager::getBool("multiple render targets", "Render")) + if (Settings::Manager::getBool("shader", "Water")) { CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 83510db13..d2b53291e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -302,7 +302,7 @@ void NIFLoader::createMaterial(const String &name, if (Settings::Manager::getBool("shaders", "Objects")) { - bool mrt = Settings::Manager::getBool("multiple render targets", "Render"); + bool mrt = Settings::Manager::getBool("shader", "Water"); // Create shader for the material // vertex diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 7791f39ab..90f832b99 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -57,9 +57,3 @@ reflect small statics = false reflect actors = true reflect misc = false - -[Render] - -# Only supported on SM3+ cards -# If you have a lower end card, this will be disabled automatically -multiple render targets = true From b36c0d95b80c565e1cb9c4f94a8b24a44891db6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 22:11:04 +0200 Subject: [PATCH 044/185] night transition fix --- apps/openmw/mwworld/weather.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 09fd20076..8422dd916 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -472,6 +472,7 @@ WeatherResult WeatherManager::transition(float factor) result.mCloudSpeed = current.mCloudSpeed; result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mGlareView = lerp(current.mGlareView, other.mGlareView); + result.mNightFade = lerp(current.mNightFade, other.mNightFade); result.mNight = current.mNight; From e718d4b6f060ec1fcbd09db83829dce84449d0fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Apr 2012 22:36:48 +0200 Subject: [PATCH 045/185] another sky fix --- apps/openmw/mwworld/weather.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8422dd916..80035df14 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -521,23 +521,23 @@ void WeatherManager::update(float duration) srand(time(NULL)); float random = ((rand()%100)/100.f) * total; - //if (random > snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) // weather = "blizzard"; - //else if (random > blight+ash+thunder+rain+overcast+foggy+cloudy+clear) + //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) // weather = "snow"; - /*else*/ if (random > ash+thunder+rain+overcast+foggy+cloudy+clear) + /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) weather = "blight"; - else if (random > thunder+rain+overcast+foggy+cloudy+clear) + else if (random >= thunder+rain+overcast+foggy+cloudy+clear) weather = "ashstorm"; - else if (random > rain+overcast+foggy+cloudy+clear) + else if (random >= rain+overcast+foggy+cloudy+clear) weather = "thunderstorm"; - else if (random > overcast+foggy+cloudy+clear) + else if (random >= overcast+foggy+cloudy+clear) weather = "rain"; - else if (random > foggy+cloudy+clear) + else if (random >= foggy+cloudy+clear) weather = "overcast"; - else if (random > cloudy+clear) + else if (random >= cloudy+clear) weather = "foggy"; - else if (random > clear) + else if (random >= clear) weather = "cloudy"; else weather = "clear"; From ef0a185e115aebe56fc12d32785e03f050895b4f Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Fri, 6 Apr 2012 01:17:23 +0300 Subject: [PATCH 046/185] Pinnable windows: hide hud elements Hide elements of the HUD (health/magicka/stamina bars, minimap) when the corresponding windows (stats/map) are pinned. Rearrange the remaining hud elements in such cases (like in the original Morrowind). --- apps/openmw/mwgui/layouts.cpp | 57 ++++++++++++++++++++++ apps/openmw/mwgui/layouts.hpp | 16 +++++- apps/openmw/mwgui/map_window.cpp | 12 ++--- apps/openmw/mwgui/map_window.hpp | 7 ++- apps/openmw/mwgui/stats_window.cpp | 5 ++ apps/openmw/mwgui/stats_window.hpp | 3 ++ apps/openmw/mwgui/window_manager.cpp | 10 ++++ apps/openmw/mwgui/window_manager.hpp | 5 ++ apps/openmw/mwgui/window_pinnable_base.cpp | 1 + apps/openmw/mwgui/window_pinnable_base.hpp | 2 + files/mygui/openmw_hud_layout.xml | 28 ++++++----- 11 files changed, 122 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/layouts.cpp index af068ffae..0bca3b534 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/layouts.cpp @@ -31,6 +31,11 @@ HUD::HUD(int width, int height, int fpsLevel) , fpscounter(NULL) , trianglecounter(NULL) , batchcounter(NULL) + , hmsBaseLeft(0) + , weapBoxBaseLeft(0) + , spellBoxBaseLeft(0) + , effectBoxBaseRight(0) + , minimapBoxBaseRight(0) { setCoord(0,0, width, height); @@ -38,16 +43,25 @@ HUD::HUD(int width, int height, int fpsLevel) getWidget(health, "Health"); getWidget(magicka, "Magicka"); getWidget(stamina, "Stamina"); + hmsBaseLeft = health->getLeft(); // Item and spell images and status bars + getWidget(weapBox, "WeapBox"); getWidget(weapImage, "WeapImage"); getWidget(weapStatus, "WeapStatus"); + weapBoxBaseLeft = weapBox->getLeft(); + + getWidget(spellBox, "SpellBox"); getWidget(spellImage, "SpellImage"); getWidget(spellStatus, "SpellStatus"); + spellBoxBaseLeft = spellBox->getLeft(); getWidget(effectBox, "EffectBox"); getWidget(effect1, "Effect1"); + effectBoxBaseRight = effectBox->getRight(); + getWidget(minimapBox, "MiniMapBox"); + minimapBoxBaseRight = minimapBox->getRight(); getWidget(minimap, "MiniMap"); getWidget(compass, "Compass"); @@ -163,15 +177,21 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& v void HUD::setPlayerDir(const float x, const float y) { + if (!minimapBox->getVisible() || (x == mLastPositionX && y == mLastPositionY)) return; + MyGUI::ISubWidget* main = compass->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); + mLastPositionX = x; + mLastPositionY = y; } void HUD::setPlayerPos(const float x, const float y) { + if (!minimapBox->getVisible() || (x == mLastDirectionX && y == mLastDirectionY)) return; + MyGUI::IntSize size = minimap->getCanvasSize(); MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); MyGUI::IntCoord viewsize = minimap->getCoord(); @@ -179,6 +199,39 @@ void HUD::setPlayerPos(const float x, const float y) minimap->setViewOffset(pos); compass->setPosition(MyGUI::IntPoint(x*512-16, y*512-16)); + + mLastDirectionX = x; + mLastDirectionY = y; +} + +void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible) +{ + int weapDx = 0, spellDx = 0; + if (!hmsVisible) + spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft; + + if (!weapVisible) + spellDx -= spellBoxBaseLeft - weapBoxBaseLeft; + + health->setVisible(hmsVisible); + stamina->setVisible(hmsVisible); + magicka->setVisible(hmsVisible); + weapBox->setPosition(weapBoxBaseLeft - weapDx, weapBox->getTop()); + weapBox->setVisible(weapVisible); + spellBox->setPosition(spellBoxBaseLeft - spellDx, spellBox->getTop()); + spellBox->setVisible(spellVisible); +} + +void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible) +{ + // effect box can have variable width -> variable left coordinate + int effectsDx = 0; + if (!minimapBoxVisible) + effectsDx = minimapBoxBaseRight - effectBoxBaseRight; + + minimapBox->setVisible(minimapBoxVisible); + effectBox->setPosition(effectBoxBaseRight - effectBox->getWidth() + effectsDx, effectBox->getTop()); + effectBox->setVisible(effectBoxVisible); } LocalMapBase::LocalMapBase() @@ -189,6 +242,10 @@ LocalMapBase::LocalMapBase() , mPrefix() , mChanged(true) , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) { } diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp index 30bea579c..42b4a8b9e 100644 --- a/apps/openmw/mwgui/layouts.hpp +++ b/apps/openmw/mwgui/layouts.hpp @@ -48,6 +48,11 @@ namespace MWGui bool mChanged; OEngine::GUI::Layout* mLayout; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; }; class HUD : public OEngine::GUI::Layout, public LocalMapBase @@ -66,11 +71,14 @@ namespace MWGui void setBatchCount(size_t count); void setPlayerDir(const float x, const float y); void setPlayerPos(const float x, const float y); + void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); + void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); MyGUI::ProgressPtr health, magicka, stamina; + MyGUI::Widget *weapBox, *spellBox; MyGUI::ImageBox *weapImage, *spellImage; MyGUI::ProgressPtr weapStatus, spellStatus; - MyGUI::WidgetPtr effectBox; + MyGUI::Widget *effectBox, *minimapBox; MyGUI::ImageBox* effect1; MyGUI::ScrollView* minimap; MyGUI::ImageBox* compass; @@ -80,6 +88,12 @@ namespace MWGui MyGUI::TextBox* fpscounter; MyGUI::TextBox* trianglecounter; MyGUI::TextBox* batchcounter; + + private: + // bottom left elements + int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; + // bottom right elements + int minimapBoxBaseRight, effectBoxBaseRight; }; class MainMenu : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index b4e8aa4d6..0e9d57c3c 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -1,7 +1,7 @@ #include "map_window.hpp" +#include "window_manager.hpp" /* #include "../mwmechanics/mechanicsmanager.hpp" -#include "window_manager.hpp" #include #include @@ -14,11 +14,7 @@ using namespace MWGui; MapWindow::MapWindow(WindowManager& parWindowManager) : MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), - mGlobal(false), - mLastPositionX(0.0f), - mLastPositionY(0.0f), - mLastDirectionX(0.0f), - mLastDirectionY(0.0f) + mGlobal(false) { setCoord(500,0,320,300); setText("WorldButton", "World"); @@ -104,3 +100,7 @@ void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) mButton->setCaption( mGlobal ? "Local" : "World" ); } +void MapWindow::onPinToggled() +{ + mWindowManager.setMinimapVisibility(!mPinned); +} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index cad652bff..d14221a40 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -26,10 +26,9 @@ namespace MWGui MyGUI::Button* mButton; MyGUI::IntPoint mLastDragPos; bool mGlobal; - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; + + protected: + virtual void onPinToggled(); }; } #endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 3ded9713a..675e5141f 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -381,3 +381,8 @@ void StatsWindow::updateScroller() skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); } + +void StatsWindow::onPinToggled() +{ + mWindowManager.setHMSVisibility(!mPinned); +} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 081a75d56..f2731e545 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -74,6 +74,9 @@ namespace MWGui std::string birthSignId; int reputation, bounty; std::vector skillWidgets; //< Skills and other information + + protected: + virtual void onPinToggled(); }; } #endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 4d7b9f901..8ad71186b 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -456,3 +456,13 @@ void WindowManager::setPlayerDir(const float x, const float y) map->setPlayerDir(x,y); hud->setPlayerDir(x,y); } + +void WindowManager::setHMSVisibility(bool visible) +{ + hud->setBottomLeftVisibility(visible, hud->weapBox->getVisible(), hud->spellBox->getVisible()); +} + +void WindowManager::setMinimapVisibility(bool visible) +{ + hud->setBottomRightVisibility(hud->effectBox->getVisible(), visible); +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 582f438e8..e8637f8a2 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -160,6 +160,11 @@ namespace MWGui void setInteriorMapTexture(const int x, const int y); ///< set the index of the map texture that should be used (for interiors) + // sets the visibility of the hud health/magicka/stamina bars + void setHMSVisibility(bool visible); + // sets the visibility of the hud minimap + void setMinimapVisibility(bool visible); + template void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr. void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 07f0ea278..ecdf311c6 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -25,6 +25,7 @@ void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std: if ("PinToggle" == eventName) { mPinned = !mPinned; + onPinToggled(); } eventDone(this); diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index f3cec847f..8ef38c386 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -17,6 +17,8 @@ namespace MWGui void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); protected: + virtual void onPinToggled() = 0; + bool mPinned; bool mVisible; }; diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 20370770e..2dafa7298 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -11,22 +11,24 @@ align="Left Bottom" name="Stamina"/> - - + + + + + - - - + + + + + - - From a41eee9a721c643368eb92909684cecb95d6a15b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 14:07:52 +0200 Subject: [PATCH 047/185] specular lighting --- apps/openmw/mwrender/renderingmanager.cpp | 1 + files/water/water.cg | 17 +++++++++++++++-- files/water/water.material | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index afa54b30c..4b38cb148 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -406,6 +406,7 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) void RenderingManager::setSunColour(const Ogre::ColourValue& colour) { mSun->setDiffuseColour(colour); + mSun->setSpecularColour(colour); mTerrainManager->setDiffuse(colour); } diff --git a/files/water/water.cg b/files/water/water.cg index 188c37709..18ef0a757 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -37,6 +37,8 @@ void main_fp , in float iDepth : TEXCOORD2 , in float4 iEyeVector : TEXCOORD3 , uniform float renderTargetFlipping + , uniform float4 lightPosObjSpace0 + , uniform float4 lightSpecularColour0 , uniform sampler2D reflectionMap : register(s0) , uniform sampler2D refractionMap : register(s1) @@ -74,11 +76,22 @@ void main_fp // tangent to object space normal.xyz = normal.xzy; + iEyeVector.xyz = normalize(iEyeVector.xyz); + // fresnel - float facing = 1.0 - max(abs(dot(normalize(iEyeVector.xyz), normal.xyz)), 0); + float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0); float reflectionFactor = saturate(0.35 + 0.65 * pow(facing, 2)); - oColor.xyz = lerp(refraction.xyz, reflection.xyz, depth1 * reflectionFactor); + // specular + float3 lightDir = normalize(lightPosObjSpace0.xyz); // assumes that light 0 is a directional light + float3 halfVector = normalize(iEyeVector + lightDir); + float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64); + + float opacity = depth1 * saturate(reflectionFactor + specular); + + reflection.xyz += lightSpecularColour0.xyz * specular; + + oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity); float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); diff --git a/files/water/water.material b/files/water/water.material index f21f929d4..d0cadfc09 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -54,6 +54,8 @@ material Water param_named_auto fogParams fog_params param_named_auto renderTargetFlipping render_target_flipping param_named_auto far far_clip_distance + param_named_auto lightPosObjSpace0 light_position_object_space 0 + param_named_auto lightSpecularColour0 light_specular_colour 0 } texture_unit reflectionMap From 393530e67174d4771cc668a2dbefcfe0c9a0f601 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 15:05:17 +0200 Subject: [PATCH 048/185] more or less fixed the sky for normal viewing angles, still disappears at a certain height though --- apps/openmw/mwrender/sky.cpp | 9 ++++++++- apps/openmw/mwrender/sky.hpp | 23 ++++++++++++----------- apps/openmw/mwrender/water.cpp | 10 ++++++---- apps/openmw/mwrender/water.hpp | 2 +- files/water/water.cg | 5 ++++- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 43ef31d86..8f719ebaa 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -810,7 +810,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) strength = 1.f; mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - mSun->setVisibility(weather.mGlareView); + + if (strength < 0.4) strength = 0.4; + mSun->setVisibility(weather.mGlareView * strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); } @@ -923,3 +925,8 @@ void SkyManager::resetSkyPosition() { mRootNode->setPosition(0,0,0); } + +void SkyManager::scaleSky(float scale) +{ + mRootNode->setScale(scale, scale, scale); +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index c18b9f484..f6f166b9e 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -170,6 +170,7 @@ namespace MWRender void setSkyPosition(const Ogre::Vector3& position); void resetSkyPosition(); + void scaleSky(float scale); private: bool mCreated; @@ -183,21 +184,21 @@ namespace MWRender BillboardObject* mSunGlare; Moon* mMasser; Moon* mSecunda; - + Ogre::Viewport* mViewport; Ogre::SceneNode* mRootNode; Ogre::SceneManager* mSceneMgr; - + Ogre::SceneNode* mAtmosphereDay; Ogre::SceneNode* mAtmosphereNight; - + Ogre::MaterialPtr mCloudMaterial; Ogre::MaterialPtr mAtmosphereMaterial; - + Ogre::MaterialPtr mStarsMaterials[7]; - + Ogre::HighLevelGpuProgramPtr mCloudFragmentShader; - + // remember some settings so we don't have to apply them again if they didnt change Ogre::String mClouds; Ogre::String mNextClouds; @@ -207,17 +208,17 @@ namespace MWRender float mStarsOpacity; Ogre::ColourValue mCloudColour; Ogre::ColourValue mSkyColour; - + Ogre::Overlay* mThunderOverlay; Ogre::TextureUnitState* mThunderTextureUnit; - + float mRemainingTransitionTime; - + float mGlare; // target float mGlareFade; // actual - + void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType); - + bool mEnabled; bool mSunEnabled; bool mMasserEnabled; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cbce0d075..544f738e5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -141,15 +141,16 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { mWater->setVisible(false); - mOldCameraFarClip = mCamera->getFarClipDistance(); - if (mReflectDistance != 0) - mCamera->setFarClipDistance(mReflectDistance); + //mOldCameraFarClip = mCamera->getFarClipDistance(); + //if (mReflectDistance != 0) + // mCamera->setFarClipDistance(mReflectDistance); if (evt.source == mReflectionTarget) { Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); + mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); } @@ -159,11 +160,12 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mWater->setVisible(true); - mCamera->setFarClipDistance(mOldCameraFarClip); + //mCamera->setFarClipDistance(mOldCameraFarClip); if (evt.source == mReflectionTarget) { mSky->resetSkyPosition(); + mSky->scaleSky(1); mCamera->disableReflection(); mCamera->disableCustomNearClipPlane(); } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 964a8c735..264f96fbe 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,7 +11,7 @@ namespace MWRender { class SkyManager; /// Water rendering - class Water : Ogre::RenderTargetListener + class Water : public Ogre::RenderTargetListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; diff --git a/files/water/water.cg b/files/water/water.cg index 18ef0a757..613891fa5 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -54,6 +54,9 @@ void main_fp float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; + // No need for transparency since we are using a refraction map + oColor.a = 1; + // Sample screen-space depth map and subtract pixel depth to get the real water depth float depth1 = tex2D(depthMap, screenCoords).r * far - iDepth; depth1 = saturate(depth1 / 500.f); @@ -93,7 +96,7 @@ void main_fp oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity); + // add fog float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); - oColor.a = 1; } From ec3fe1ef002ef7aa6e0dd66eb1cd256a6b344d1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 15:17:54 +0200 Subject: [PATCH 049/185] no sun glare in the reflection --- apps/openmw/mwrender/renderconst.hpp | 3 +++ apps/openmw/mwrender/sky.cpp | 6 ++++++ apps/openmw/mwrender/sky.hpp | 23 ++++++++++++----------- apps/openmw/mwrender/water.cpp | 3 +-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 26d56a75c..4445ffe6b 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -47,6 +47,9 @@ enum VisibilityFlags RV_Sky = 64, + // Sun glare (not visible in reflection) + RV_Glare = 128, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, /// \todo markers (normally hidden) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8f719ebaa..fdd9cd511 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -60,6 +60,11 @@ Vector3 BillboardObject::getPosition() const return Vector3(p.x, -p.z, p.y); } +void BillboardObject::setVisibilityFlags(int flags) +{ + mBBSet->setVisibilityFlags(flags); +} + void BillboardObject::setColour(const ColourValue& pColour) { mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour); @@ -421,6 +426,7 @@ void SkyManager::create() mSun->setRenderQueue(RQG_SkiesEarly+4); mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode); mSunGlare->setRenderQueue(RQG_SkiesLate); + mSunGlare->setVisibilityFlags(RV_Glare); HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f6f166b9e..64d5c16a0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -36,24 +36,25 @@ namespace MWRender BillboardObject(); virtual ~BillboardObject() {} - + void setColour(const Ogre::ColourValue& pColour); void setPosition(const Ogre::Vector3& pPosition); void setVisible(const bool visible); void setRenderQueue(unsigned int id); + void setVisibilityFlags(int flags); void setSize(const float size); Ogre::Vector3 getPosition() const; - + void setVisibility(const float visibility); - + Ogre::SceneNode* getNode(); - + protected: virtual void init(const Ogre::String& textureName, const float size, const Ogre::Vector3& position, Ogre::SceneNode* rootNode); - + Ogre::SceneNode* mNode; Ogre::MaterialPtr mMaterial; Ogre::BillboardSet* mBBSet; @@ -71,9 +72,9 @@ namespace MWRender const Ogre::Vector3& position, Ogre::SceneNode* rootNode ); - + virtual ~Moon() {} - + enum Phase { Phase_New = 0, @@ -85,20 +86,20 @@ namespace MWRender Phase_WaningHalf, Phase_WaningCrescent }; - + enum Type { Type_Masser = 0, Type_Secunda }; - + void setPhase(const Phase& phase); void setType(const Type& type); void setSkyColour(const Ogre::ColourValue& colour); - + Phase getPhase() const; unsigned int getPhaseInt() const; - + private: Type mType; Phase mPhase; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 544f738e5..574261863 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -139,14 +139,13 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { - mWater->setVisible(false); - //mOldCameraFarClip = mCamera->getFarClipDistance(); //if (mReflectDistance != 0) // mCamera->setFarClipDistance(mReflectDistance); if (evt.source == mReflectionTarget) { + mWater->setVisible(false); Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); From 2976625b0024ad4b02b508970edcf0cceb3297f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 15:51:57 +0200 Subject: [PATCH 050/185] better underwater --- apps/openmw/mwrender/water.cpp | 40 ++++++++++++++++++++++++++-------- apps/openmw/mwrender/water.hpp | 3 ++- files/water/water.cg | 2 ++ files/water/water.material | 4 ++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 574261863..dd06e2181 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -69,7 +69,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mReflectionTarget = rtt; } - mWater->setMaterial(createMaterial()); + createMaterial(); + mWater->setMaterial(mMaterial); } void Water::setActive(bool active) @@ -120,6 +121,15 @@ void Water::checkUnderwater(float y) try { CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); } catch(...) {} + + // tell the shader we are not underwater + Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); + if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) + pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0)); + + if (mReflectionTarget) + mReflectionTarget->setActive(mActive); + mIsUnderwater = false; } @@ -128,6 +138,15 @@ void Water::checkUnderwater(float y) try { CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); } catch(...) {} + + // tell the shader we are underwater + Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); + if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) + pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1)); + + if (mReflectionTarget) + mReflectionTarget->setActive(false); + mIsUnderwater = true; } } @@ -146,10 +165,15 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) if (evt.source == mReflectionTarget) { mWater->setVisible(false); + + // Some messy code to get the skybox to show up at all + // The problem here is that it gets clipped by the water plane + // Therefore scale it up a bit Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); + mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); } @@ -170,9 +194,9 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) } } -Ogre::MaterialPtr Water::createMaterial() +void Water::createMaterial() { - MaterialPtr mat = MaterialManager::getSingleton().getByName("Water"); + mMaterial = MaterialManager::getSingleton().getByName("Water"); // these have to be set in code std::string textureNames[32]; @@ -180,28 +204,26 @@ Ogre::MaterialPtr Water::createMaterial() { textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; } - mat->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); + mMaterial->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); // use technique without shaders if reflection is disabled if (mReflectionTarget == 0) - mat->removeTechnique(0); + mMaterial->removeTechnique(0); if (Settings::Manager::getBool("shader", "Water")) { CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); - TextureUnitState* tus = mat->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); + TextureUnitState* tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); if (tus != 0) tus->setTexture(colorTexture); TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); - tus = mat->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap"); + tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap"); if (tus != 0) tus->setTexture(depthTexture); } - - return mat; } void Water::setViewportBackground(const ColourValue& bg) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 264f96fbe..855dd3b18 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -34,7 +34,8 @@ namespace MWRender { SkyManager* mSky; - Ogre::MaterialPtr createMaterial(); + void createMaterial(); + Ogre::MaterialPtr mMaterial; Ogre::RenderTarget* mReflectionTarget; diff --git a/files/water/water.cg b/files/water/water.cg index 613891fa5..dfb1972ae 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -48,6 +48,7 @@ void main_fp , uniform float far , uniform float4 fogParams , uniform float4 fogColour + , uniform float isUnderwater ) { @@ -91,6 +92,7 @@ void main_fp float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64); float opacity = depth1 * saturate(reflectionFactor + specular); + opacity *= (1-isUnderwater); reflection.xyz += lightSpecularColour0.xyz * specular; diff --git a/files/water/water.material b/files/water/water.material index d0cadfc09..cf7a414cf 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -43,6 +43,8 @@ material Water { pass { + cull_hardware none + vertex_program_ref Water_VP { param_named_auto camPosObjSpace camera_position_object_space @@ -56,6 +58,7 @@ material Water param_named_auto far far_clip_distance param_named_auto lightPosObjSpace0 light_position_object_space 0 param_named_auto lightSpecularColour0 light_specular_colour 0 + param_named isUnderwater float 0 } texture_unit reflectionMap @@ -85,6 +88,7 @@ material Water scheme Map pass { + cull_hardware none scene_blend alpha_blend depth_write off diffuse 0 0 0 1 From c169f9e171f740869bc6df9954973d4ed91243d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 16:11:08 +0200 Subject: [PATCH 051/185] underwater tweaks --- apps/openmw/mwrender/renderconst.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 7 +++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 4445ffe6b..ab411a6cb 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -18,6 +18,8 @@ enum RenderQueueGroups RQG_Alpha = Ogre::RENDER_QUEUE_7, + RQG_UnderWater = Ogre::RENDER_QUEUE_7+1, + RQG_OcclusionQuery = Ogre::RENDER_QUEUE_8, // Sky late (sun & sun flare) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4b38cb148..2f85d3599 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -54,6 +54,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const if (caps->getNumMultiRenderTargets() < 2) Settings::Manager::setBool("shader", "Water", false); + // note that the order is important here if (useMRT()) { CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); @@ -61,6 +62,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer"); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); } + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Water"); // Turn the entire scene (represented by the 'root' node) -90 // degrees around the x axis. This makes Z go upwards, and Y go into diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index dd06e2181..89b40cf63 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -16,7 +16,6 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : try { - CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1); CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); } catch(...) {} @@ -76,7 +75,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : void Water::setActive(bool active) { mActive = active; - if (mReflectionTarget) mReflectionTarget->setActive(active); + if (mReflectionTarget) mReflectionTarget->setActive(active && !mIsUnderwater); mWater->setVisible(active); } @@ -130,6 +129,8 @@ void Water::checkUnderwater(float y) if (mReflectionTarget) mReflectionTarget->setActive(mActive); + mWater->setRenderQueueGroup(RQG_Water); + mIsUnderwater = false; } @@ -147,6 +148,8 @@ void Water::checkUnderwater(float y) if (mReflectionTarget) mReflectionTarget->setActive(false); + mWater->setRenderQueueGroup(RQG_UnderWater); + mIsUnderwater = true; } } From 114e8ae2a02b54f3cb34945cba13816e69cbb923 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 16:45:45 +0200 Subject: [PATCH 052/185] much less underwater distortion --- files/water/GlassFP.cg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/water/GlassFP.cg b/files/water/GlassFP.cg index 0ce343b0a..1e6c53984 100644 --- a/files/water/GlassFP.cg +++ b/files/water/GlassFP.cg @@ -9,7 +9,7 @@ float4 main_ps(float2 iTexCoord : TEXCOORD0, float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; - return tex2D(RT, iTexCoord + normal.xy * 0.05) + + return tex2D(RT, iTexCoord + normal.xy * 0.015) + (tex2D(CausticMap, noiseCoord) / 5) + tintColour ; } From 8316a4c2ecb37195435f6b25328a28e6286acab1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 17:21:56 +0200 Subject: [PATCH 053/185] add mrt dummy output to sky shaders --- apps/openmw/mwrender/sky.cpp | 51 +++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index fdd9cd511..d22f20a22 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -13,6 +13,7 @@ #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "renderconst.hpp" +#include "renderingmanager.hpp" using namespace MWRender; using namespace Ogre; @@ -152,14 +153,20 @@ void BillboardObject::init(const String& textureName, outStream2 << "void main_fp( \n" " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" + " out float4 oColor : COLOR, \n"; + if (RenderingManager::useMRT()) outStream2 << + " out float4 oColor1 : COLOR1, \n"; + outStream2 << " 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) * tex * float4(1,1,1,diffuse.a); \n" + " oColor = float4(emissive.xyz,1) * tex * float4(1,1,1,diffuse.a); \n"; + if (RenderingManager::useMRT()) outStream2 << + " oColor1 = float4(1, 0, 0, 1); \n"; + outStream2 << "}"; fshader->setSource(outStream2.str()); fshader->load(); @@ -215,7 +222,10 @@ Moon::Moon( const String& textureName, outStream2 << "void main_fp( \n" " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" + " out float4 oColor : COLOR, \n"; + if (RenderingManager::useMRT()) outStream2 << + " out float4 oColor1 : COLOR1, \n"; + outStream2 << " uniform sampler2D texture : TEXUNIT0, \n" " uniform float4 skyColour, \n" " uniform float4 diffuse, \n" @@ -223,7 +233,10 @@ Moon::Moon( const String& textureName, ") \n" "{ \n" " float4 tex = tex2D(texture, uv); \n" - " oColor = float4(emissive.xyz,1) * tex; \n" + " oColor = float4(emissive.xyz,1) * tex; \n"; + if (RenderingManager::useMRT()) outStream2 << + " oColor1 = float4(1, 0, 0, 1); \n"; + outStream2 << // use a circle for the alpha (compute UV distance to center) // looks a bit bad because its not filtered on the edges, // but it's cheaper than a seperate alpha texture. @@ -474,7 +487,10 @@ void SkyManager::create() outStream5 << "void main_fp( \n" " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" + " out float4 oColor : COLOR, \n"; + if (RenderingManager::useMRT()) outStream5 << + " out float4 oColor1 : COLOR1, \n"; + outStream5 << " in float fade : TEXCOORD1, \n" " uniform sampler2D texture : TEXUNIT0, \n" " uniform float opacity, \n" @@ -482,7 +498,10 @@ void SkyManager::create() " uniform float4 emissive \n" ") \n" "{ \n" - " oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n" + " oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"; + if (RenderingManager::useMRT()) outStream5 << + " oColor1 = float4(1, 0, 0, 1); \n"; + outStream5 << "}"; stars_fp->setSource(outStream5.str()); stars_fp->load(); @@ -551,11 +570,17 @@ void SkyManager::create() _outStream << "void main_fp( \n" " in float4 iVertexColor : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" + " out float4 oColor : COLOR, \n"; + if (RenderingManager::useMRT()) _outStream << + " out float4 oColor1 : COLOR1, \n"; + _outStream << " uniform float4 emissive \n" ") \n" "{ \n" - " oColor = iVertexColor * emissive; \n" + " oColor = iVertexColor * emissive; \n"; + if (RenderingManager::useMRT()) _outStream << + " oColor1 = float4(1, 0, 0, 1); \n"; + _outStream << "}"; fshader->setSource(_outStream.str()); fshader->load(); @@ -607,8 +632,11 @@ void SkyManager::create() outStream2 << "void main_fp( \n" " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" " in float4 color : TEXCOORD1, \n" + " out float4 oColor : COLOR, \n"; + if (RenderingManager::useMRT()) outStream2 << + " out float4 oColor1 : COLOR1, \n"; + outStream2 << " uniform sampler2D texture : TEXUNIT0, \n" " uniform sampler2D secondTexture : TEXUNIT1, \n" " uniform float transitionFactor, \n" @@ -620,7 +648,10 @@ void SkyManager::create() "{ \n" " uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in 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" + " oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"; + if (RenderingManager::useMRT()) outStream2 << + " oColor1 = float4(1, 0, 0, 1); \n"; + outStream2 << "}"; mCloudFragmentShader->setSource(outStream2.str()); mCloudFragmentShader->load(); From 456eb9520985fce0ac77f755b0cbcefb49fbb97e Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 18:22:37 +0200 Subject: [PATCH 054/185] reversed sun and moon paths (sunrise at east) --- apps/openmw/mwrender/renderingmanager.cpp | 6 +- apps/openmw/mwrender/water.cpp | 7 +- apps/openmw/mwrender/water.hpp | 2 + apps/openmw/mwworld/weather.cpp | 12 +- files/water/water.cg | 6 +- files/water/water.compositor | 29 ++++- files/water/water.material | 147 ++++++++++++++-------- 7 files changed, 145 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2f85d3599..362a04ca5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -61,8 +61,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer"); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater"); + } + else + { + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "UnderwaterNoMRT"); } - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Water"); // Turn the entire scene (represented by the 'root' node) -90 // degrees around the x axis. This makes Z go upwards, and Y go into diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 89b40cf63..615a24a76 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,6 +1,7 @@ #include "water.hpp" #include #include "sky.hpp" +#include "renderingmanager.hpp" using namespace Ogre; @@ -68,6 +69,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mReflectionTarget = rtt; } + mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT"; + createMaterial(); mWater->setMaterial(mMaterial); } @@ -118,7 +121,7 @@ void Water::checkUnderwater(float y) if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { try { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); + CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); } catch(...) {} // tell the shader we are not underwater @@ -137,7 +140,7 @@ void Water::checkUnderwater(float y) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { try { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); + CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true); } catch(...) {} // tell the shader we are underwater diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 855dd3b18..b5aa29a5b 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -34,6 +34,8 @@ namespace MWRender { SkyManager* mSky; + std::string mCompositorName; + void createMaterial(); Ogre::MaterialPtr mMaterial; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 80035df14..0d86d36ca 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -585,8 +585,8 @@ void WeatherManager::update(float duration) int facing = (mHour > 13.f) ? 1 : -1; Vector3 final( - (1-height)*facing, - (1-height)*facing, + -(1-height)*facing, + -(1-height)*facing, height); mRendering->setSunDirection(final); @@ -606,13 +606,13 @@ void WeatherManager::update(float duration) float moonHeight = 1-std::abs((night-0.5)*2); int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1; Vector3 masser( - (1-moonHeight)*facing, - (1-moonHeight)*facing, + -(1-moonHeight)*facing, + -(1-moonHeight)*facing, moonHeight); Vector3 secunda( - (1-moonHeight)*facing*0.8, - (1-moonHeight)*facing*1.25, + -(1-moonHeight)*facing*0.8, + -(1-moonHeight)*facing*1.25, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); diff --git a/files/water/water.cg b/files/water/water.cg index dfb1972ae..85c86f3b6 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -19,9 +19,9 @@ void main_vp oDepth = oPos.z; float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5, - 0, -0.5, 0, 0.5, - 0, 0, 0.5, 0.5, - 0, 0, 0, 1 ); + 0, -0.5, 0, 0.5, + 0, 0, 0.5, 0.5, + 0, 0, 0, 1 ); float4 texcoordProj = mul(scalemat, oPos); oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); diff --git a/files/water/water.compositor b/files/water/water.compositor index 67bf90896..8d9c3cb39 100644 --- a/files/water/water.compositor +++ b/files/water/water.compositor @@ -1,4 +1,4 @@ -compositor Water +compositor UnderwaterNoMRT { technique { @@ -6,6 +6,30 @@ compositor Water target rt0 { input previous } + target_output + { + // Start with clear output + input none + + pass render_quad + { + material Water/CompositorNoMRT + input 0 rt0 + } + } + } +} + + +compositor Underwater +{ + technique + { + texture_ref scene gbuffer mrt_output + texture rt0 target_width target_height PF_R8G8B8 + + target rt0 { input previous } + target_output { // Start with clear output @@ -15,7 +39,8 @@ compositor Water { material Water/Compositor input 0 rt0 + input 3 scene 1 } } } -} +} diff --git a/files/water/water.material b/files/water/water.material index cf7a414cf..3afbaacd5 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -1,21 +1,21 @@ vertex_program Water/GlassVP cg { - source GlassVP.cg - entry_point glass_vp - profiles vs_1_1 arbvp1 - - default_params - { - param_named_auto worldViewProj worldviewproj_matrix - } + source GlassVP.cg + entry_point glass_vp + profiles vs_1_1 arbvp1 + + default_params + { + param_named_auto worldViewProj worldviewproj_matrix + } } fragment_program Water/GlassFP cg { - source GlassFP.cg - entry_point main_ps - profiles ps_2_0 arbfp1 + source GlassFP.cg + entry_point main_ps + profiles ps_2_0 arbfp1 } vertex_program Water_VP cg @@ -104,45 +104,92 @@ material Water } } +material Water/CompositorNoMRT +{ + technique + { + pass + { + depth_check off + vertex_program_ref Water/GlassVP + { + param_named_auto timeVal time 0.25 + param_named scale float 0.1 + } + + fragment_program_ref Water/GlassFP + { + param_named tintColour float4 0 0.35 0.35 1 + } + + texture_unit RT + { + tex_coord_set 0 + tex_address_mode clamp + filtering linear linear linear + } + + texture_unit + { + texture WaterNormal2.tga 2d + tex_coord_set 1 + //tex_address_mode clamp + filtering linear linear linear + } + texture_unit + { + texture caustic_0.png 2d + tex_coord_set 2 + //tex_address_mode clamp + filtering linear linear linear + } + } + } +} + material Water/Compositor { - technique - { - pass - { - depth_check off - vertex_program_ref Water/GlassVP - { - param_named_auto timeVal time 0.25 - param_named scale float 0.1 - } - - fragment_program_ref Water/GlassFP - { - param_named tintColour float4 0 0.35 0.35 1 - } - - texture_unit RT - { - tex_coord_set 0 - tex_address_mode clamp - filtering linear linear linear - } - - texture_unit - { - texture WaterNormal2.tga 2d - tex_coord_set 1 - //tex_address_mode clamp - filtering linear linear linear - } - texture_unit - { - texture caustic_0.png 2d - tex_coord_set 2 - //tex_address_mode clamp - filtering linear linear linear - } - } - } + technique + { + pass + { + depth_check off + vertex_program_ref Water/GlassVP + { + param_named_auto timeVal time 0.25 + param_named scale float 0.1 + } + + fragment_program_ref Water/GlassFP + { + param_named tintColour float4 0 0.35 0.35 1 + } + + texture_unit RT + { + tex_coord_set 0 + tex_address_mode clamp + filtering linear linear linear + } + + texture_unit + { + texture WaterNormal2.tga 2d + tex_coord_set 2 + //tex_address_mode clamp + filtering linear linear linear + } + texture_unit + { + texture caustic_0.png 2d + tex_coord_set 3 + //tex_address_mode clamp + filtering linear linear linear + } + + texture_unit DepthMap + { + } + } + } } From c0f991ac0ae4353da2f6a9f81dc883e846b411cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 18:51:30 +0200 Subject: [PATCH 055/185] underwater depth effect --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- files/CMakeLists.txt | 3 +- files/water/GlassFP.cg | 15 ------ files/water/GlassVP.cg | 24 --------- files/water/underwater.cg | 61 +++++++++++++++++++++++ files/water/water.cg | 3 ++ files/water/water.material | 39 ++++++++------- 7 files changed, 87 insertions(+), 60 deletions(-) delete mode 100644 files/water/GlassFP.cg delete mode 100644 files/water/GlassVP.cg create mode 100644 files/water/underwater.cg diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 362a04ca5..8d84af98f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -59,9 +59,9 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const { CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer"); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); + CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater"); CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer"); CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater"); } else { diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 377e2d1f8..507f82c1a 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,8 +1,7 @@ project(resources) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassFP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassFP.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassVP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassVP.cg" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/underwater.cg "${OpenMW_BINARY_DIR}/resources/water/underwater.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) diff --git a/files/water/GlassFP.cg b/files/water/GlassFP.cg deleted file mode 100644 index 1e6c53984..000000000 --- a/files/water/GlassFP.cg +++ /dev/null @@ -1,15 +0,0 @@ - -float4 main_ps(float2 iTexCoord : TEXCOORD0, - float3 noiseCoord : TEXCOORD1, - uniform sampler2D RT : register(s0), - uniform sampler2D NormalMap : register(s1), - uniform sampler2D CausticMap : register(s2), - uniform float4 tintColour) : COLOR -{ - float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; - - - return tex2D(RT, iTexCoord + normal.xy * 0.015) + - (tex2D(CausticMap, noiseCoord) / 5) + - tintColour ; -} diff --git a/files/water/GlassVP.cg b/files/water/GlassVP.cg deleted file mode 100644 index 71153769c..000000000 --- a/files/water/GlassVP.cg +++ /dev/null @@ -1,24 +0,0 @@ -void glass_vp -( - in float4 inPos : POSITION, - - out float4 pos : POSITION, - out float2 uv0 : TEXCOORD0, - out float4 noiseCoord : TEXCOORD1, - - uniform float4x4 worldViewProj, - uniform float timeVal, - uniform float scale -) -{ - // Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc) - pos = mul(worldViewProj, inPos); - - // The input positions adjusted by texel offsets, so clean up inaccuracies - inPos.xy = sign(inPos.xy); - - // Convert to image-space - uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f; - noiseCoord = (pos + timeVal) * scale; -} - diff --git a/files/water/underwater.cg b/files/water/underwater.cg new file mode 100644 index 000000000..a734c316f --- /dev/null +++ b/files/water/underwater.cg @@ -0,0 +1,61 @@ +void main_vp +( + in float4 inPos : POSITION, + + out float4 pos : POSITION, + out float2 uv0 : TEXCOORD0, + out float4 noiseCoord : TEXCOORD1, + + uniform float4x4 worldViewProj, + uniform float timeVal, + uniform float scale +) +{ + // Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc) + pos = mul(worldViewProj, inPos); + + // The input positions adjusted by texel offsets, so clean up inaccuracies + inPos.xy = sign(inPos.xy); + + // Convert to image-space + uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f; + noiseCoord = (pos + timeVal) * scale; +} + + + +float4 main_fp_nomrt (float2 iTexCoord : TEXCOORD0, + float3 noiseCoord : TEXCOORD1, + uniform sampler2D RT : register(s0), + uniform sampler2D NormalMap : register(s1), + uniform sampler2D CausticMap : register(s2), + uniform float4 tintColour) : COLOR +{ + float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; + + return tex2D(RT, iTexCoord + normal.xy * 0.015) + + (tex2D(CausticMap, noiseCoord) / 5) + + tintColour ; +} + + +float4 main_fp (float2 iTexCoord : TEXCOORD0, + float3 noiseCoord : TEXCOORD1, + uniform float far, + uniform sampler2D RT : register(s0), + uniform sampler2D NormalMap : register(s1), + uniform sampler2D CausticMap : register(s2), + uniform sampler2D DepthMap : register(s3), + uniform float4 tintColour) : COLOR +{ + float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; + + float depth = tex2D(DepthMap, iTexCoord).r * far; + depth = saturate(depth / 2000.f); + + float4 color = tex2D(RT, iTexCoord + normal.xy * 0.015) + + (tex2D(CausticMap, noiseCoord) / 5) + + tintColour; + + return lerp(color, float4(0, 0.65, 0.65, 1), depth); +} diff --git a/files/water/water.cg b/files/water/water.cg index 85c86f3b6..a3393e3bf 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -98,6 +98,9 @@ void main_fp oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity); + oColor.xyz += isUnderwater * float3(0, 0.35, 0.35); // underwater tint color + oColor.xyz = lerp(oColor.xyz, float3(0, 0.65, 0.65), saturate(isUnderwater * (iDepth / 2000.f))); // underwater fog + // add fog float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); diff --git a/files/water/water.material b/files/water/water.material index 3afbaacd5..1b8573c4a 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -1,7 +1,7 @@ -vertex_program Water/GlassVP cg +vertex_program UnderwaterEffectVP cg { - source GlassVP.cg - entry_point glass_vp + source underwater.cg + entry_point main_vp profiles vs_1_1 arbvp1 default_params @@ -11,10 +11,17 @@ vertex_program Water/GlassVP cg } -fragment_program Water/GlassFP cg +fragment_program UnderwaterEffectFP_NoMRT cg { - source GlassFP.cg - entry_point main_ps + source underwater.cg + entry_point main_fp_nomrt + profiles ps_2_0 arbfp1 +} + +fragment_program UnderwaterEffectFP cg +{ + source underwater.cg + entry_point main_fp profiles ps_2_0 arbfp1 } @@ -111,13 +118,13 @@ material Water/CompositorNoMRT pass { depth_check off - vertex_program_ref Water/GlassVP + vertex_program_ref UnderwaterEffectVP { param_named_auto timeVal time 0.25 param_named scale float 0.1 } - fragment_program_ref Water/GlassFP + fragment_program_ref UnderwaterEffectFP_NoMRT { param_named tintColour float4 0 0.35 0.35 1 } @@ -154,37 +161,33 @@ material Water/Compositor pass { depth_check off - vertex_program_ref Water/GlassVP + vertex_program_ref UnderwaterEffectVP { param_named_auto timeVal time 0.25 param_named scale float 0.1 } - fragment_program_ref Water/GlassFP + fragment_program_ref UnderwaterEffectFP { param_named tintColour float4 0 0.35 0.35 1 + param_named_auto far far_clip_distance } texture_unit RT { - tex_coord_set 0 + tex_coord_set 0 tex_address_mode clamp - filtering linear linear linear } texture_unit { texture WaterNormal2.tga 2d - tex_coord_set 2 - //tex_address_mode clamp - filtering linear linear linear + tex_coord_set 2 } texture_unit { texture caustic_0.png 2d - tex_coord_set 3 - //tex_address_mode clamp - filtering linear linear linear + tex_coord_set 3 } texture_unit DepthMap From f008ca166b1140a2f8c5ac068b57cc7040456729 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 19:21:28 +0200 Subject: [PATCH 056/185] restored moons like they were --- apps/openmw/mwworld/weather.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 0d86d36ca..4a5586f55 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -606,13 +606,13 @@ void WeatherManager::update(float duration) float moonHeight = 1-std::abs((night-0.5)*2); int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1; Vector3 masser( - -(1-moonHeight)*facing, - -(1-moonHeight)*facing, + (1-moonHeight)*facing, + (1-moonHeight)*facing, moonHeight); Vector3 secunda( - -(1-moonHeight)*facing*0.8, - -(1-moonHeight)*facing*1.25, + (1-moonHeight)*facing*0.8, + (1-moonHeight)*facing*1.25, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); From c49d5dd40bc8c044e0194f1b6a9fb0f312a8582d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 19:23:19 +0200 Subject: [PATCH 057/185] another sky tweak --- apps/openmw/mwrender/sky.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d22f20a22..188ec3b83 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -848,7 +848,6 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); - if (strength < 0.4) strength = 0.4; mSun->setVisibility(weather.mGlareView * strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); From bcee5d5943592584fb39921686301088ecbd1133 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 6 Apr 2012 19:40:37 +0200 Subject: [PATCH 058/185] fix areas with only water (no objects below) --- files/water/water.cg | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/water/water.cg b/files/water/water.cg index a3393e3bf..bbd42874b 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -59,8 +59,10 @@ void main_fp oColor.a = 1; // Sample screen-space depth map and subtract pixel depth to get the real water depth - float depth1 = tex2D(depthMap, screenCoords).r * far - iDepth; + float depthTex = tex2D(depthMap, screenCoords).r; + float depth1 = depthTex * far - iDepth; depth1 = saturate(depth1 / 500.f); + depth1 = (depthTex == 0 ? 1 : depth1); // Simple wave effect. to be replaced by something better float2 uv1 = iUv + time * float2(0.5, 0); From 87e8917c4dc3a4a7df0a02f0e935aa3c3e965eb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 6 Apr 2012 10:43:14 -0700 Subject: [PATCH 059/185] Don't try to play sounds when no sound output is initialized --- apps/openmw/mwsound/openal_output.cpp | 4 ++++ apps/openmw/mwsound/sound_output.hpp | 4 ++++ apps/openmw/mwsound/soundmanager.cpp | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 610a797a2..9959bedc8 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -508,6 +508,8 @@ void OpenAL_Output::init(const std::string &devname) } if(mFreeSources.empty()) fail("Could not allocate any sources"); + + mInitialized = true; } void OpenAL_Output::deinit() @@ -535,6 +537,8 @@ void OpenAL_Output::deinit() if(mDevice) alcCloseDevice(mDevice); mDevice = 0; + + mInitialized = false; } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 774e42efa..7efed8129 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -35,15 +35,19 @@ namespace MWSound Sound_Output(const Sound_Output &rhs); protected: + bool mInitialized; Ogre::Vector3 mPos; Sound_Output(SoundManager &mgr) : mManager(mgr) + , mInitialized(false) , mPos(0.0f, 0.0f, 0.0f) { } public: virtual ~Sound_Output() { } + bool isInitialized() { return mInitialized; } + friend class OpenAL_Output; friend class SoundManager; }; diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 145390e3e..eaa18e6dc 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -136,6 +136,8 @@ namespace MWSound void SoundManager::streamMusicFull(const std::string& filename) { + if(!mOutput->isInitialized()) + return; std::cout <<"Playing "<isInitialized()) + return; try { // The range values are not tested @@ -210,6 +214,8 @@ namespace MWSound SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) { SoundPtr sound; + if(!mOutput->isInitialized()) + return sound; try { float basevol = 1.0f; /* TODO: volume settings */ @@ -237,6 +243,8 @@ namespace MWSound float volume, float pitch, int mode) { SoundPtr sound; + if(!mOutput->isInitialized()) + return sound; try { // Look up the sound in the ESM data @@ -450,6 +458,8 @@ namespace MWSound void SoundManager::update(float duration) { + if(!mOutput->isInitialized()) + return; updateSounds(duration); updateRegionSound(duration); } From 72b3f6121d25a7fd036de25ebabc5952d16c67fb Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Sat, 7 Apr 2012 12:37:15 +0300 Subject: [PATCH 060/185] Windows Pinning: add files to CMakeLists.txt Add new files (map_window and window_pinnable_base) --- apps/openmw/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3dabc9ac8..e4f618eb9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,6 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation + map_window window_pinnable_base ) add_openmw_dir (mwdialogue From e21e8c221d3ba16700d37ea5cda0b5624d0c6d48 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 7 Apr 2012 12:54:30 +0200 Subject: [PATCH 061/185] Added explicit cast to char in ToUTF8::windows_XXXX tables. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added explicit cast to char, without that gcc 4.7 (with default settings) is showing a lot of: narrowing conversion of ‘...’ from ‘int’ to ‘char’ inside { } is ill-formed in C++11 [-Wnarrowing] warnings. --- components/to_utf8/gen_iconv.cpp | 2 +- components/to_utf8/tables_gen.hpp | 1536 ++++++++++++++--------------- 2 files changed, 769 insertions(+), 769 deletions(-) diff --git a/components/to_utf8/gen_iconv.cpp b/components/to_utf8/gen_iconv.cpp index 620205245..b7298e304 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/to_utf8/gen_iconv.cpp @@ -12,7 +12,7 @@ void tab() { cout << " "; } // write one number with a space in front of it and a comma after it void num(unsigned char i, bool last) { - cout << " 0x" << (unsigned)i; + cout << " (char)0x" << (unsigned)i; if(!last) cout << ","; } diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index 79945bddc..1084ca28f 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -10,785 +10,785 @@ namespace ToUTF8 /// Serbian (Latin script), Romanian and Albanian. static char windows_1250[] = { - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x9, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xb, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xc, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xd, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xe, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xf, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x11, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x13, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x14, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x15, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x16, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x17, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x18, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x19, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x21, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x22, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x23, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x24, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x25, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x26, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x27, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x28, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x29, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x30, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x31, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x32, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x33, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x35, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x36, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x38, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x39, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x41, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x42, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x43, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x44, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x45, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x46, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x47, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x48, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x49, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x50, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x51, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x52, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x53, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x55, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x56, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x57, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x58, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x59, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x60, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x61, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x62, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x66, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x67, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x68, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x69, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x70, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x71, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x72, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x73, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x74, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x75, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x76, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x77, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x78, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x79, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x82, 0xac, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0x9a, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0x9e, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa6, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa1, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0xb0, 0x0, 0x0, - 0x2, 0xc5, 0xa0, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xb9, 0x0, 0x0, - 0x2, 0xc5, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xb9, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0x98, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x99, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9c, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9d, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa2, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x93, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x94, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x84, 0xa2, 0x0, 0x0, - 0x2, 0xc5, 0xa1, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xba, 0x0, 0x0, - 0x2, 0xc5, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xa5, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa0, 0x0, 0x0, 0x0, - 0x2, 0xcb, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xcb, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x81, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa8, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x9e, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xac, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xcb, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb4, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb5, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb8, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x85, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x9f, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xcb, 0x9d, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xbc, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x94, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x81, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0xb9, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x86, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x8c, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x89, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8b, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8d, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8e, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x8e, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x90, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x83, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x93, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x94, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x90, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x96, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x97, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9c, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9d, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xa2, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9f, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x95, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa1, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa2, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x83, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x8d, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x99, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x8f, 0x0, 0x0, 0x0, - 0x2, 0xc4, 0x91, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x88, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb3, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb4, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x91, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0x99, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xaf, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbc, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xa3, 0x0, 0x0, 0x0, - 0x2, 0xcb, 0x99, 0x0, 0x0, 0x0 + (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x8, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x9, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xa, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xb, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xc, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xd, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xe, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xf, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x10, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x11, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x12, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x13, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x14, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x15, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x16, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x17, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x18, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x19, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x21, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x22, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x23, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x24, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x25, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x26, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x27, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x28, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x29, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x30, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x31, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x32, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x33, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x34, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x35, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x36, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x37, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x38, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x39, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x40, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x41, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x42, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x43, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x44, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x45, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x46, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x47, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x48, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x49, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x50, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x51, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x52, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x53, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x54, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x55, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x56, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x57, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x58, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x59, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x60, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x61, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x62, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x63, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x64, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x65, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x66, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x67, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x68, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x69, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x70, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x71, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x72, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x73, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x74, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x75, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x76, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x77, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x78, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x79, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x82, (char)0xac, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0x9a, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0x9e, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa6, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa1, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0xb0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xb9, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xb9, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0x98, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x99, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9c, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9d, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa2, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x93, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x94, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x84, (char)0xa2, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xba, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x81, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x9e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xac, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x85, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x9f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x9d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xbc, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x94, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x81, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0xb9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x86, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x8c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x89, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x8e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x90, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x83, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x93, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x94, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x90, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x96, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x97, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x95, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x83, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x8d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x99, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x8f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc4, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x88, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x99, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xaf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbc, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x99, (char)0x0, (char)0x0, (char)0x0 }; /// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic /// and other languages static char windows_1251[] = { - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x9, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xb, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xc, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xd, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xe, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xf, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x11, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x13, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x14, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x15, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x16, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x17, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x18, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x19, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x21, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x22, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x23, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x24, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x25, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x26, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x27, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x28, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x29, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x30, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x31, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x32, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x33, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x35, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x36, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x38, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x39, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x41, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x42, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x43, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x44, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x45, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x46, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x47, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x48, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x49, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x50, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x51, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x52, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x53, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x55, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x56, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x57, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x58, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x59, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x60, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x61, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x62, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x66, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x67, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x68, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x69, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x70, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x71, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x72, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x73, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x74, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x75, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x76, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x77, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x78, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x79, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x83, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9a, 0x0, 0x0, - 0x2, 0xd1, 0x93, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9e, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa6, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa1, 0x0, 0x0, - 0x3, 0xe2, 0x82, 0xac, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xb0, 0x0, 0x0, - 0x2, 0xd0, 0x89, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xb9, 0x0, 0x0, - 0x2, 0xd0, 0x8a, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x8c, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x8b, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x8f, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x92, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x98, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x99, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9c, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9d, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa2, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x93, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x94, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x84, 0xa2, 0x0, 0x0, - 0x2, 0xd1, 0x99, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xba, 0x0, 0x0, - 0x2, 0xd1, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x9c, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x9f, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa0, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x8e, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x9e, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x88, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xd2, 0x90, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x81, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xac, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x86, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x96, 0x0, 0x0, 0x0, - 0x2, 0xd2, 0x91, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb5, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x91, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x84, 0x96, 0x0, 0x0, - 0x2, 0xd1, 0x94, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x85, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x95, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x97, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x90, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x91, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x92, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x93, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x94, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x95, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x96, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x97, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x99, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9c, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9d, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9e, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0x9f, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa0, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa1, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa2, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa3, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa5, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa6, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa8, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xaa, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xac, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xaf, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb2, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb3, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb4, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb5, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb8, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xb9, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xbc, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xd0, 0xbf, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x80, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x81, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x83, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x85, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x86, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x88, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x89, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8a, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8b, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8c, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8d, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8e, 0x0, 0x0, 0x0, - 0x2, 0xd1, 0x8f, 0x0, 0x0, 0x0 + (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x8, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x9, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xa, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xb, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xc, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xd, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xe, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xf, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x10, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x11, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x12, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x13, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x14, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x15, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x16, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x17, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x18, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x19, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x21, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x22, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x23, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x24, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x25, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x26, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x27, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x28, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x29, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x30, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x31, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x32, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x33, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x34, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x35, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x36, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x37, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x38, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x39, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x40, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x41, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x42, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x43, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x44, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x45, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x46, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x47, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x48, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x49, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x50, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x51, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x52, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x53, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x54, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x55, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x56, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x57, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x58, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x59, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x60, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x61, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x62, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x63, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x64, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x65, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x66, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x67, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x68, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x69, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x70, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x71, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x72, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x73, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x74, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x75, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x76, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x77, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x78, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x79, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x83, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9a, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x93, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9e, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa6, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa1, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x82, (char)0xac, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xb0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x89, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xb9, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x8a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x8c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x8b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x8f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x92, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x98, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x99, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9c, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9d, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa2, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x93, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x94, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x84, (char)0xa2, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x99, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xba, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x9c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x9f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x8e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x9e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x88, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd2, (char)0x90, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x81, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xac, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x86, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x96, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd2, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x84, (char)0x96, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x94, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x85, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x95, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x97, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x90, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x92, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x93, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x94, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x95, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x96, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x97, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x99, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0x9f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xaa, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xac, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xaf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xb9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xbc, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd0, (char)0xbf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x80, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x81, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x83, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x85, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x86, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x88, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x89, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xd1, (char)0x8f, (char)0x0, (char)0x0, (char)0x0 }; /// Latin alphabet used by English and some other Western languages static char windows_1252[] = { - 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x8, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x9, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xa, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xb, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xc, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xd, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xe, 0x0, 0x0, 0x0, 0x0, - 0x1, 0xf, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x10, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x11, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x12, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x13, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x14, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x15, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x16, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x17, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x18, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x19, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x1f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x21, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x22, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x23, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x24, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x25, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x26, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x27, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x28, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x29, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x2f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x30, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x31, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x32, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x33, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x34, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x35, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x36, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x37, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x38, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x39, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x3f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x40, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x41, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x42, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x43, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x44, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x45, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x46, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x47, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x48, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x49, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x4f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x50, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x51, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x52, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x53, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x54, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x55, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x56, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x57, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x58, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x59, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x5f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x60, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x61, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x62, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x63, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x64, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x65, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x66, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x67, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x68, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x69, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x6f, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x70, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x71, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x72, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x73, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x74, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x75, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x76, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x77, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x78, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x79, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7a, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7b, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7c, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7d, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7e, 0x0, 0x0, 0x0, 0x0, - 0x1, 0x7f, 0x0, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x82, 0xac, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0x9a, 0x0, 0x0, - 0x2, 0xc6, 0x92, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9e, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa6, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa1, 0x0, 0x0, - 0x2, 0xcb, 0x86, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xb0, 0x0, 0x0, - 0x2, 0xc5, 0xa0, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xb9, 0x0, 0x0, - 0x2, 0xc5, 0x92, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x2, 0xc5, 0xbd, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x3, 0xe2, 0x80, 0x98, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x99, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9c, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x9d, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xa2, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x93, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0x94, 0x0, 0x0, - 0x2, 0xcb, 0x9c, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x84, 0xa2, 0x0, 0x0, - 0x2, 0xc5, 0xa1, 0x0, 0x0, 0x0, - 0x3, 0xe2, 0x80, 0xba, 0x0, 0x0, - 0x2, 0xc5, 0x93, 0x0, 0x0, 0x0, - 0x1, 0x20, 0x0, 0x0, 0x0, 0x0, // not part of this charset - 0x2, 0xc5, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xc5, 0xb8, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa0, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa1, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa2, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa3, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa5, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa8, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xaa, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xac, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xaf, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb2, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb3, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb4, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb5, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb8, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xb9, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbc, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xc2, 0xbf, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x80, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x81, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x82, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x83, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x84, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x85, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x86, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x87, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x88, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x89, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8a, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8b, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8c, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8d, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8e, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x8f, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x90, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x91, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x92, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x93, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x94, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x95, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x96, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x97, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x98, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x99, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9a, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9b, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9c, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9d, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9e, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0x9f, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa0, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa1, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa2, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa3, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa4, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa5, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa6, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa7, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa8, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xa9, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xaa, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xab, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xac, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xad, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xae, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xaf, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb0, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb1, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb2, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb3, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb4, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb5, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb6, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb7, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb8, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xb9, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xba, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbb, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbc, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbd, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbe, 0x0, 0x0, 0x0, - 0x2, 0xc3, 0xbf, 0x0, 0x0, 0x0 + (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x8, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x9, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xa, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xb, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xc, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xd, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xe, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0xf, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x10, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x11, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x12, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x13, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x14, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x15, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x16, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x17, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x18, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x19, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x1f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x21, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x22, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x23, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x24, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x25, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x26, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x27, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x28, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x29, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x2f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x30, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x31, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x32, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x33, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x34, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x35, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x36, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x37, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x38, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x39, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x3f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x40, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x41, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x42, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x43, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x44, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x45, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x46, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x47, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x48, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x49, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x4f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x50, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x51, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x52, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x53, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x54, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x55, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x56, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x57, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x58, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x59, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x5f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x60, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x61, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x62, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x63, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x64, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x65, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x66, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x67, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x68, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x69, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x6f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x70, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x71, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x72, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x73, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x74, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x75, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x76, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x77, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x78, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x79, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7a, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7b, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7c, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7d, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7e, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x7f, (char)0x0, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x82, (char)0xac, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0x9a, (char)0x0, (char)0x0, + (char)0x2, (char)0xc6, (char)0x92, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9e, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa6, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa1, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x86, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xb0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xb9, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x92, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x2, (char)0xc5, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x3, (char)0xe2, (char)0x80, (char)0x98, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x99, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9c, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x9d, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xa2, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x93, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0x94, (char)0x0, (char)0x0, + (char)0x2, (char)0xcb, (char)0x9c, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x84, (char)0xa2, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x3, (char)0xe2, (char)0x80, (char)0xba, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0x93, (char)0x0, (char)0x0, (char)0x0, + (char)0x1, (char)0x20, (char)0x0, (char)0x0, (char)0x0, (char)0x0, // not part of this charset + (char)0x2, (char)0xc5, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc5, (char)0xb8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xaa, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xac, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xaf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xb9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbc, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc2, (char)0xbf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x80, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x81, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x82, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x83, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x84, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x85, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x86, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x87, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x88, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x89, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x8f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x90, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x91, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x92, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x93, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x94, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x95, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x96, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x97, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x98, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x99, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9a, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9b, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9c, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9d, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9e, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0x9f, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xa9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xaa, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xab, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xac, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xad, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xae, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xaf, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb0, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb1, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb2, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb3, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb4, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb5, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb6, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb7, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb8, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xb9, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xba, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbb, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbc, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbd, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbe, (char)0x0, (char)0x0, (char)0x0, + (char)0x2, (char)0xc3, (char)0xbf, (char)0x0, (char)0x0, (char)0x0 }; } From 1bf79fd022232ca7ecd5e4904324fc48c8cf9609 Mon Sep 17 00:00:00 2001 From: Roman Melnik Date: Sat, 7 Apr 2012 16:47:41 +0300 Subject: [PATCH 062/185] Windows pinning: support for MapWindow Set correct skin for the Map Window. --- files/mygui/openmw_map_window_layout.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_map_window_layout.xml b/files/mygui/openmw_map_window_layout.xml index f5c2c9991..fbba8ddf4 100644 --- a/files/mygui/openmw_map_window_layout.xml +++ b/files/mygui/openmw_map_window_layout.xml @@ -1,7 +1,7 @@ - + From dbf75470035b0b92b49bea0c60a8772ca9a40726 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 16:33:03 +0200 Subject: [PATCH 063/185] fixed first weather transition being instant --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4a5586f55..d92a36c83 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -341,7 +341,6 @@ void WeatherManager::setWeather(const String& weather, bool instant) { mNextWeather = ""; mCurrentWeather = weather; - mFirstUpdate = false; } else { @@ -355,6 +354,7 @@ void WeatherManager::setWeather(const String& weather, bool instant) mNextWeather = weather; mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600; } + mFirstUpdate = false; } WeatherResult WeatherManager::getResult(const String& weather) From 96c37d3e7cea65d64dd7273eb9d375d3f789f33c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 16:55:32 +0200 Subject: [PATCH 064/185] more accurate fog, TODO: apply this to the terrain --- apps/openmw/mwworld/weather.cpp | 5 ++++- components/nifogre/ogre_nif_loader.cpp | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d92a36c83..fb0480171 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -334,8 +334,11 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E void WeatherManager::setWeather(const String& weather, bool instant) { - if (weather == mCurrentWeather && mNextWeather == "") + if (weather == mCurrentWeather && mNextWeather == "") + { + mFirstUpdate = false; return; + } if (instant || mFirstUpdate) { diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d2b53291e..886c4b451 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,6 +328,7 @@ void NIFLoader::createMaterial(const String &name, " out float4 oNormal : TEXCOORD2, \n" " out float oDepth : TEXCOORD3, \n" " out float4 oVertexColour : TEXCOORD4, \n" + " uniform float4 cameraPosObjSpace, \n" " uniform float4x4 worldViewProj \n" ") \n" "{ \n" @@ -335,12 +336,13 @@ void NIFLoader::createMaterial(const String &name, " oUV = uv; \n" " oNormal = normal; \n" " oPosition = mul( worldViewProj, position ); \n" - " oDepth = oPosition.z; \n" + " oDepth = length(position.xyz - cameraPosObjSpace.xyz); \n" " oPositionObjSpace = position; \n" "}"; vertex->setSource(outStream.str()); vertex->load(); vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); + vertex->getDefaultParameters()->setNamedAutoConstant("cameraPosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); } else vertex = mgr.getByName("main_vp"); From 12f7bae526b89aecb024b5f61d2cd77528e5c602 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Apr 2012 18:37:41 +0200 Subject: [PATCH 065/185] added known spells and selected spell to NpcStats --- apps/openmw/mwmechanics/npcstats.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index aeb5f56d5..59bfa2ac0 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -2,6 +2,7 @@ #define GAME_MWMECHANICS_NPCSTATS_H #include +#include #include "stat.hpp" @@ -25,6 +26,9 @@ namespace MWMechanics bool mSneak; bool mCombat; + std::set mKnownSpells; + std::string mSelectedSpell; // can be an empty string (no spell selected) + NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), mCombat (false) {} }; From c94d6830145dcad282e8c3ac412308746c8692a2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Apr 2012 18:46:50 +0200 Subject: [PATCH 066/185] fill in initial spell list from NPC record --- apps/openmw/mwclass/npc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a94d27d..2cf4cf41c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -61,6 +61,10 @@ namespace MWClass for (int i=0; i<27; ++i) data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); + for (std::vector::const_iterator iter (ref->base->spells.list.begin()); + iter!=ref->base->spells.list.end(); ++iter) + data->mNpcStats.mKnownSpells.insert (*iter); + // creature stats data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); From d5a7d418dd5176621dedc89e4153af49dab33bf9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Apr 2012 19:53:49 +0200 Subject: [PATCH 067/185] added getValue function to Class hierarchy --- apps/openmw/mwclass/apparatus.cpp | 8 ++++++++ apps/openmw/mwclass/apparatus.hpp | 3 +++ apps/openmw/mwclass/armor.cpp | 8 ++++++++ apps/openmw/mwclass/armor.hpp | 3 +++ apps/openmw/mwclass/book.cpp | 8 ++++++++ apps/openmw/mwclass/book.hpp | 3 +++ apps/openmw/mwclass/clothing.cpp | 8 ++++++++ apps/openmw/mwclass/clothing.hpp | 3 +++ apps/openmw/mwclass/ingredient.cpp | 8 ++++++++ apps/openmw/mwclass/ingredient.hpp | 3 +++ apps/openmw/mwclass/light.cpp | 8 ++++++++ apps/openmw/mwclass/light.hpp | 3 +++ apps/openmw/mwclass/lockpick.cpp | 8 ++++++++ apps/openmw/mwclass/lockpick.hpp | 3 +++ apps/openmw/mwclass/misc.cpp | 8 ++++++++ apps/openmw/mwclass/misc.hpp | 3 +++ apps/openmw/mwclass/potion.cpp | 8 ++++++++ apps/openmw/mwclass/potion.hpp | 3 +++ apps/openmw/mwclass/probe.cpp | 8 ++++++++ apps/openmw/mwclass/probe.hpp | 3 +++ apps/openmw/mwclass/repair.cpp | 8 ++++++++ apps/openmw/mwclass/repair.hpp | 3 +++ apps/openmw/mwclass/weapon.cpp | 8 ++++++++ apps/openmw/mwclass/weapon.hpp | 3 +++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 4 ++++ 26 files changed, 141 insertions(+) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index e95fb572f..4562057de 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -70,6 +70,14 @@ namespace MWClass return ref->base->script; } + int Apparatus::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Apparatus::registerSelf() { boost::shared_ptr instance (new Apparatus); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index c0849e1fe..861610f6c 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index e1c2734f0..dfc40882c 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -160,6 +160,14 @@ namespace MWClass return ESM::Skill::HeavyArmor; } + int Armor::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Armor::registerSelf() { boost::shared_ptr instance (new Armor); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 2b66ff828..de5ca3983 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -40,6 +40,9 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 0a81ebafb..08811d2aa 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -72,6 +72,14 @@ namespace MWClass return ref->base->script; } + int Book::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Book::registerSelf() { boost::shared_ptr instance (new Book); diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index ccbbfb4b2..4738187cd 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 4fe19ada4..aa58822f9 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -123,6 +123,14 @@ namespace MWClass return -1; } + int Clothing::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Clothing::registerSelf() { boost::shared_ptr instance (new Clothing); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 171b06246..97e09012d 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -34,6 +34,9 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 1a7edf632..84e7ba12a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -68,6 +68,14 @@ namespace MWClass return ref->base->script; } + int Ingredient::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Ingredient::registerSelf() { boost::shared_ptr instance (new Ingredient); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 9463dcf8d..2d7717672 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index e2e63a89b..9c31706dc 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -110,6 +110,14 @@ namespace MWClass return std::make_pair (slots, false); } + int Light::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Light::registerSelf() { boost::shared_ptr instance (new Light); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 46a4d60ba..bde252c28 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -34,6 +34,9 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 3dda2f4af..b55a5e41c 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -81,6 +81,14 @@ namespace MWClass return std::make_pair (slots, false); } + int Lockpick::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Lockpick::registerSelf() { boost::shared_ptr instance (new Lockpick); diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0c9189c54..1b56234af 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -29,6 +29,9 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 864fc1e38..ef82cc277 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -70,6 +70,14 @@ namespace MWClass return ref->base->script; } + int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Miscellaneous::registerSelf() { boost::shared_ptr instance (new Miscellaneous); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index b07964f99..fc002280c 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 4ab374590..e2c889484 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -70,6 +70,14 @@ namespace MWClass return ref->base->script; } + int Potion::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Potion::registerSelf() { boost::shared_ptr instance (new Potion); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index be9e713fb..7d3017937 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 4b4d79a73..1e9840334 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -80,6 +80,14 @@ namespace MWClass return std::make_pair (slots, false); } + int Probe::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Probe::registerSelf() { boost::shared_ptr instance (new Probe); diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 1507d65aa..232b52364 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -29,6 +29,9 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 758bf4079..1f12e699d 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -70,6 +70,14 @@ namespace MWClass return ref->base->script; } + int Repair::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Repair::registerSelf() { boost::shared_ptr instance (new Repair); diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 17b606f4c..0a9d9c253 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -25,6 +25,9 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 20db0cf38..9b4db4654 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -139,6 +139,14 @@ namespace MWClass return -1; } + int Weapon::getValue (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->data.value; + } + void Weapon::registerSelf() { boost::shared_ptr instance (new Weapon); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index f863c0bfe..505c45645 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -40,6 +40,9 @@ namespace MWClass /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. + virtual int getValue (const MWWorld::Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9d766909f..d3a0a34ae 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -137,6 +137,11 @@ namespace MWWorld return -1; } + int Class::getValue (const Ptr& ptr) const + { + throw std::logic_error ("value not supported by this class"); + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 67320b3e0..e474e9b92 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -155,6 +155,10 @@ namespace MWWorld /// no such skill. /// (default implementation: return -1) + virtual int getValue (const Ptr& ptr) const; + ///< Return trade value of the object. Throws an exception, if the object can't be traded. + /// (default implementation: throws an exception) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. From 34a02fef45f0d02dc455ca77d24ce00ac5770da1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 7 Apr 2012 20:09:09 +0200 Subject: [PATCH 068/185] consider item value when auto equipping --- apps/openmw/mwworld/inventorystore.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index aedd119c8..1fe76a0a8 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -101,20 +101,30 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { + Ptr test = *iter; + std::pair, bool> itemsSlots = MWWorld::Class::get (*iter).getEquipmentSlots (*iter); for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { - /// \todo comapre item with item in slot - if (slots.at (*iter2)==end()) + if (slots.at (*iter2)!=end()) { - /// \todo unstack, if reqquired (itemsSlots.second) - - slots[*iter2] = iter; - break; + Ptr old = *slots.at (*iter2); + + // check value + if (MWWorld::Class::get (old).getValue (old)>=MWWorld::Class::get (test).getValue (test)) + { + /// \todo check skill + continue; + } } + + /// \todo unstack, if reqquired (itemsSlots.second) + + slots[*iter2] = iter; + break; } } From 96911ada953c3b47756c3437235529f9fe400422 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 22:37:15 +0200 Subject: [PATCH 069/185] restored render queue of transparent objects, they are now part of the mrt textures this fixes some issues with transparent objects not visible in the refraction --- apps/openmw/mwrender/renderconst.hpp | 4 ++-- components/nifogre/ogre_nif_loader.cpp | 2 +- files/gbuffer/gbuffer.compositor | 9 ++++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index ab411a6cb..76a460a16 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -14,9 +14,9 @@ enum RenderQueueGroups RQG_Main = Ogre::RENDER_QUEUE_MAIN, - RQG_Water = Ogre::RENDER_QUEUE_6, + RQG_Water = Ogre::RENDER_QUEUE_7+1, - RQG_Alpha = Ogre::RENDER_QUEUE_7, + RQG_Alpha = Ogre::RENDER_QUEUE_MAIN, RQG_UnderWater = Ogre::RENDER_QUEUE_7+1, diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 886c4b451..538e7290d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -420,7 +420,7 @@ void NIFLoader::createMaterial(const String &name, " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << - " oColor1 = float4(iDepth / far, 0, 0, 1); \n"; + " oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1 outStream << "}"; diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index 8ab5665dd..6ca35df87 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -16,8 +16,9 @@ compositor gbuffer } pass render_scene { + // Renders everything except water first_render_queue 0 - last_render_queue 59 + last_render_queue 70 } } @@ -35,7 +36,9 @@ compositor gbuffer } } -// Finalizer compositor to render objects that we don't want in the MRT textures (this is the case for most transparent stuff) +// Finalizer compositor to render objects that we don't want in the MRT textures (ex. water) +// NB the water has to be rendered in a seperate compositor anyway, because it +// accesses the MRT textures which can't be done while they are still being rendered to. compositor gbufferFinalizer { technique @@ -63,7 +66,7 @@ compositor gbufferFinalizer } pass render_scene { - first_render_queue 60 + first_render_queue 71 last_render_queue 100 } } From cdea19206cb83a12adf09726a15ef902c15085a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 22:47:39 +0200 Subject: [PATCH 070/185] Revert "more accurate fog, TODO: apply this to the terrain" This reverts commit 96c37d3e7cea65d64dd7273eb9d375d3f789f33c. --- apps/openmw/mwworld/weather.cpp | 5 +---- components/nifogre/ogre_nif_loader.cpp | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index fb0480171..d92a36c83 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -334,11 +334,8 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E void WeatherManager::setWeather(const String& weather, bool instant) { - if (weather == mCurrentWeather && mNextWeather == "") - { - mFirstUpdate = false; + if (weather == mCurrentWeather && mNextWeather == "") return; - } if (instant || mFirstUpdate) { diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 538e7290d..835534eff 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,7 +328,6 @@ void NIFLoader::createMaterial(const String &name, " out float4 oNormal : TEXCOORD2, \n" " out float oDepth : TEXCOORD3, \n" " out float4 oVertexColour : TEXCOORD4, \n" - " uniform float4 cameraPosObjSpace, \n" " uniform float4x4 worldViewProj \n" ") \n" "{ \n" @@ -336,13 +335,12 @@ void NIFLoader::createMaterial(const String &name, " oUV = uv; \n" " oNormal = normal; \n" " oPosition = mul( worldViewProj, position ); \n" - " oDepth = length(position.xyz - cameraPosObjSpace.xyz); \n" + " oDepth = oPosition.z; \n" " oPositionObjSpace = position; \n" "}"; vertex->setSource(outStream.str()); vertex->load(); vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - vertex->getDefaultParameters()->setNamedAutoConstant("cameraPosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); } else vertex = mgr.getByName("main_vp"); From c748252d33cb87ac3ffb21e08c318717339f26d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 22:55:25 +0200 Subject: [PATCH 071/185] weather fix again --- apps/openmw/mwrender/renderconst.hpp | 2 -- apps/openmw/mwworld/weather.cpp | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 76a460a16..2c7f9e9ac 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -55,8 +55,6 @@ enum VisibilityFlags RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, /// \todo markers (normally hidden) - - RV_All = 255 }; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d92a36c83..fb0480171 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -334,8 +334,11 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E void WeatherManager::setWeather(const String& weather, bool instant) { - if (weather == mCurrentWeather && mNextWeather == "") + if (weather == mCurrentWeather && mNextWeather == "") + { + mFirstUpdate = false; return; + } if (instant || mFirstUpdate) { From 9169c0d7c9f9792a8249f0eace000dde275e4f7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 23:18:08 +0200 Subject: [PATCH 072/185] slightly improved the quality of the default water setting --- files/settings-default.cfg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index b421730dc..051f081e8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -55,10 +55,9 @@ fog end factor = 1.0 num lights = 8 [Water] - shader = false -rtt size = 256 +rtt size = 512 reflect terrain = true From 030060e656fc6e7cafc314133c8f2701455f959c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 7 Apr 2012 23:29:36 +0200 Subject: [PATCH 073/185] settings description --- files/settings-default.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 051f081e8..e3a5ceb7b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -55,6 +55,8 @@ fog end factor = 1.0 num lights = 8 [Water] +# Enable this to get fancy-looking water with reflections and refractions +# All the settings below have no effect if this is false shader = false rtt size = 512 From bf5a009299cb52cfc2f755303f49cbe32be3eb3f Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 7 Apr 2012 23:33:54 +0200 Subject: [PATCH 074/185] Some improvements to the windows installer --- CMakeLists.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71f36fe3d..7b87e3544 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,7 +346,10 @@ if(WIN32) FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*") INSTALL(FILES ${files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") - INSTALL(FILES "${OpenMW_SOURCE_DIR}/readme.txt" DESTINATION ".") + INSTALL(FILES + "${OpenMW_SOURCE_DIR}/readme.txt" + "${OpenMW_BINARY_DIR}/settings-default.cfg" + DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") @@ -356,8 +359,12 @@ if(WIN32) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;esmtool;Esmtool;omwlauncher;OpenMW Launcher") - set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher") + SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") + SET(CPACK_NSIS_DELETE_ICONS_EXTRA " + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP + Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Readme.lnk\\\" + ") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_RESOURCE_FILE_LICENSE "${OpenMW_SOURCE_DIR}/GPL3.txt") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") From b8be867e6e3bca87668bcb7f2f2e0fc9b5af07a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 7 Apr 2012 14:58:52 -0700 Subject: [PATCH 075/185] Work around a bug in the Windows OpenAL router --- apps/openmw/mwsound/openal_output.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 9959bedc8..615def701 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -467,10 +467,15 @@ void OpenAL_Output::init(const std::string &devname) else fail("Failed to open \""+devname+"\""); } - if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT")) - std::cout << "Opened \""< Date: Sat, 7 Apr 2012 15:28:38 -0700 Subject: [PATCH 076/185] Add a setting to select the sound device name --- apps/openmw/mwsound/soundmanager.cpp | 15 ++++++++++++++- files/settings-default.cfg | 4 ++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index eaa18e6dc..a09a4b056 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" @@ -64,7 +65,19 @@ namespace MWSound for(size_t i = 0;i < names.size();i++) std::cout <<" "<init(); + std::string devname = Settings::Manager::getString("device", "Sound"); + try + { + mOutput->init(devname); + } + catch(std::exception &e) + { + if(devname.empty()) + throw; + std::cout <<"Failed to open device \""<init(); + Settings::Manager::setString("device", "Sound", ""); + } } catch(std::exception &e) { diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f616471cc..71637c326 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -53,3 +53,7 @@ fog end factor = 1.0 [Terrain] # Max. number of lights that affect the terrain. Setting to 1 will only reflect sunlight num lights = 8 + +[Sound] +# Device name. Blank means default +device = From 59ccab0b2ce69e3485bc3d1b65da65d578365ba6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 7 Apr 2012 16:00:30 -0700 Subject: [PATCH 077/185] Add sound volume settings --- apps/openmw/mwsound/soundmanager.cpp | 22 ++++++++++++++++------ apps/openmw/mwsound/soundmanager.hpp | 4 ++++ files/settings-default.cfg | 5 +++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index a09a4b056..730d9d9b2 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -50,11 +50,20 @@ namespace MWSound : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) , mEnvironment(environment) , mOutput(new DEFAULT_OUTPUT(*this)) - + , mMasterVolume(1.0f) + , mSFXVolume(1.0f) + , mMusicVolume(1.0f) { if(!useSound) return; + mMasterVolume = Settings::Manager::getFloat("master volume", "Sound"); + mMasterVolume = std::min(std::max(mMasterVolume, 0.0f), 1.0f); + mSFXVolume = Settings::Manager::getFloat("sfx volume", "Sound"); + mSFXVolume = std::min(std::max(mSFXVolume, 0.0f), 1.0f); + mMusicVolume = Settings::Manager::getFloat("music volume", "Sound"); + mMusicVolume = std::min(std::max(mMusicVolume, 0.0f), 1.0f); + std::cout << "Sound output: " << SOUND_OUT << std::endl; std::cout << "Sound decoder: " << SOUND_IN << std::endl; @@ -154,9 +163,10 @@ namespace MWSound std::cout <<"Playing "<streamSound(filename, 0.4f, 1.0f, Play_NoEnv); - mMusic->mBaseVolume = 0.4f; + mMusic = mOutput->streamSound(filename, basevol, 1.0f, Play_NoEnv); + mMusic->mBaseVolume = basevol; mMusic->mFlags = Play_NoEnv; } catch(std::exception &e) @@ -200,7 +210,7 @@ namespace MWSound try { // The range values are not tested - float basevol = 1.0f; /* TODO: volume settings */ + float basevol = mMasterVolume * mSFXVolume; std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getCellRef().pos; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); @@ -231,7 +241,7 @@ namespace MWSound return sound; try { - float basevol = 1.0f; /* TODO: volume settings */ + float basevol = mMasterVolume * mSFXVolume; float min, max; std::string file = lookup(soundId, basevol, min, max); @@ -261,7 +271,7 @@ namespace MWSound try { // Look up the sound in the ESM data - float basevol = 1.0f; /* TODO: volume settings */ + float basevol = mMasterVolume * mSFXVolume; float min, max; std::string file = lookup(soundId, basevol, min, max); const ESM::Position &pos = ptr.getCellRef().pos; diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index cad5f6187..d64db299b 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -56,6 +56,10 @@ namespace MWSound std::auto_ptr mOutput; + float mMasterVolume; + float mSFXVolume; + float mMusicVolume; + boost::shared_ptr mMusic; std::string mCurrentPlaylist; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 71637c326..878b9b095 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -57,3 +57,8 @@ num lights = 8 [Sound] # Device name. Blank means default device = + +# Volumes. Sfx and music volumes are both affected by the master volume +master volume = 1.0 +sfx volume = 1.0 +music volume = 0.4 From ebab98a8a0f919049a6fd7c2997387c29f580be0 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 7 Apr 2012 22:02:20 -0400 Subject: [PATCH 078/185] Restructuring things --- CMakeLists.txt | 5 +- apps/openmw/mwclass/npc.cpp | 5 +- apps/openmw/mwrender/actors.cpp | 4 +- apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 11 +- apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/npcanimation.cpp | 182 ++++++++++++++------------ apps/openmw/mwrender/npcanimation.hpp | 21 ++- 8 files changed, 121 insertions(+), 113 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce5d84684..60eadc49a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,10 +114,7 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h - ${LIBDIR}/openengine/bullet/pmove.h - ${LIBDIR}/openengine/bullet/pmove.cpp - ${LIBDIR}/openengine/bullet/trace.h - ${LIBDIR}/openengine/bullet/trace.cpp + ) set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 94bcbb31f..c78a7501f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -93,8 +93,9 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - std::cout << "Inserting NPC\n"; - renderingInterface.getActors().insertNPC(ptr); + + + renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 6eb4a182b..5034e72b3 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -20,10 +20,10 @@ Actors::~Actors(){ void Actors::setMwRoot(Ogre::SceneNode* root){ mMwRoot = root; } -void Actors::insertNPC(const MWWorld::Ptr& ptr){ +void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend); + NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend, inv); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index d49c6e0f8..66c98c541 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -34,7 +34,7 @@ namespace MWRender{ 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); + void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fb710443b..d0019154e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -9,7 +9,6 @@ namespace MWRender{ , mRend(_rend) , mEnvironment(_env) , vecRotPos() - , shapeparts() , time(0.0f) , startTime(0.0f) , stopTime(0.0f) @@ -19,7 +18,6 @@ namespace MWRender{ , shapeNumber(0) , shapeIndexI() , shapes(NULL) - , entityparts() , transformations(NULL) , textmappings(NULL) , base(NULL) @@ -430,14 +428,7 @@ namespace MWRender{ //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::iterator iter; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7692c7128..98f0e7487 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,7 +31,7 @@ class Animation{ - std::vector* > shapeparts; //All the NiTriShape data that we need for animating an npc + float time; float startTime; @@ -48,7 +48,7 @@ class Animation{ //Ogre::SkeletonInstance* skel; std::vector* shapes; //All the NiTriShapeData for a creature - std::vector entityparts; + std::vector* transformations; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a4fd15b74..30c28bb79 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,7 @@ #include "../mwworld/world.hpp" + using namespace Ogre; using namespace NifOgre; namespace MWRender{ @@ -10,11 +11,12 @@ NpcAnimation::~NpcAnimation(){ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){ +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv){ ESMS::LiveCellRef *ref = ptr.get(); - - + Ogre::Entity* blank = 0; + std::vector* blankshape = 0; + chest = std::make_pair(blank, blankshape); //Part selection on last character of the file string // " Tri Chest // * Tri Tail @@ -95,85 +97,85 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O 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 *chestPart = 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 *groinpart = 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 *neckpart = 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); + const ESM::BodyPart *feetpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); + const ESM::BodyPart *tailpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail"); + const ESM::BodyPart *wristlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two + const ESM::BodyPart *forearmlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two + const ESM::BodyPart *handlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two + const ESM::BodyPart *hairpart = mEnvironment.mWorld->getStore().bodyParts.search(hairID); + const ESM::BodyPart *headpart = 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"); + forearmlpart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two + if(!handlpart) + handlpart = 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* handrpart = handlpart; + const ESM::BodyPart* forearmr = forearmlpart; + const ESM::BodyPart* wristrpart = wristlpart; const ESM::BodyPart* armr = arml; if(upperleg){ - insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg"); - insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg"); + lUpperLeg = insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg"); + rUpperLeg = insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg"); } if(foot){ if(bodyRaceID.compare("b_n_khajiit_m_") == 0) { - feet = foot; + feetpart = foot; } else { - insertBoundedPart("meshes\\" + foot->model, "Right Foot"); - insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot"); + rfoot = insertBoundedPart("meshes\\" + foot->model, "Right Foot"); + lfoot = insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot"); } } - if(groin){ - insertBoundedPart("meshes\\" + groin->model, "Groin"); + if(groinpart){ + groin = insertBoundedPart("meshes\\" + groinpart->model, "Groin"); } if(knee) { - insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e - insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e + lKnee = insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e + rKnee = 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"); + lAnkle = insertBoundedPart("meshes\\" + ankle->model + "*|", "Left Ankle"); //Ogre::Quaternion(Ogre::Radian(3.14 / 4), Ogre::Vector3(1, 0, 0)),blank); //1,0,0, blank); + rAnkle = insertBoundedPart("meshes\\" + ankle->model, "Right Ankle"); } if (armr){ - insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm"); + rupperArm = insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm"); } if(arml){ - insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm"); + lupperArm = insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm"); } if (forearmr) { - insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm"); + rForearm = insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm"); } - if(forearml) - insertBoundedPart("meshes\\" + forearml->model + "*|", "Left Forearm"); + if(forearmlpart) + lForearm = insertBoundedPart("meshes\\" + forearmlpart->model + "*|", "Left Forearm"); - if (wristr) + if (wristrpart) { - insertBoundedPart("meshes\\" + wristr->model, "Right Wrist"); + rWrist = insertBoundedPart("meshes\\" + wristrpart->model, "Right Wrist"); } - if(wristl) - insertBoundedPart("meshes\\" + wristl->model + "*|", "Left Wrist"); + if(wristlpart) + lWrist = insertBoundedPart("meshes\\" + wristlpart->model + "*|", "Left Wrist"); @@ -184,35 +186,35 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O if(clavicler) insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/ - if(neck) + if(neckpart) { - insertBoundedPart("meshes\\" + neck->model, "Neck"); + neck = insertBoundedPart("meshes\\" + neckpart->model, "Neck"); } - if(head) - insertBoundedPart("meshes\\" + head->model, "Head"); - if(hair) - insertBoundedPart("meshes\\" + hair->model, "Head"); + if(headpart) + head = insertBoundedPart("meshes\\" + headpart->model, "Head"); + if(hairpart) + hair = insertBoundedPart("meshes\\" + hairpart->model, "Head"); - if (chest){ - insertFreePart("meshes\\" + chest->model, ":\"", insert); + if (chestPart){ + chest = insertFreePart("meshes\\" + chestPart->model, ":\""); } - if (handr){ - insertFreePart("meshes\\" + handr->model , ":?", insert); + if (handrpart){ + rhand = insertFreePart("meshes\\" + handrpart->model , ":?"); } - if (handl){ - insertFreePart("meshes\\" + handl->model, ":>", insert); + if (handlpart){ + lhand = insertFreePart("meshes\\" + handlpart->model, ":>"); } - if(tail){ - insertFreePart("meshes\\" + tail->model, ":*", insert); + if(tailpart){ + tail = insertFreePart("meshes\\" + tailpart->model, ":*"); } - if(feet){ - std::string num = getUniqueID(feet->model); - insertFreePart("meshes\\" + feet->model,":<", insert); - insertFreePart("meshes\\" + feet->model,"::", insert); + if(feetpart){ + + lBeastFoot = insertFreePart("meshes\\" + feetpart->model,"::"); + rBeastFoot = insertFreePart("meshes\\" + feetpart->model,":<"); } //originalpos = insert->_getWorldAABB().getCenter(); //originalscenenode = insert->getPosition(); @@ -222,34 +224,38 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ NIFLoader::load(mesh); - Entity* ent = mRend.getScene()->createEntity(mesh); + Ogre::Entity* part = mRend.getScene()->createEntity(mesh); - base->attachObjectToBone(bonename, ent); - return ent; + base->attachObjectToBone(bonename, part); + return part; } -void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert){ +std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix){ + std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix; NIFLoader::load(meshNumbered); - Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered); + Ogre::Entity* part = 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()); + insert->attachObject(part); + + std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix)); + if(shape){ + + handleShapes(shape, part, base->getSkeleton()); } - - + std::pair*> pair = std::make_pair(part, shape); + return pair; } void NpcAnimation::runAnimation(float timepassed){ - + + mStateID = inv.getStateId(); + + //1. Add the amount of time passed to time //2. Handle the animation transforms dependent on time @@ -269,21 +275,25 @@ void NpcAnimation::runAnimation(float timepassed){ handleAnimationTransforms(); - std::vector*>::iterator shapepartsiter = shapeparts.begin(); - std::vector::iterator entitypartsiter = entityparts.begin(); - while(shapepartsiter != shapeparts.end()) - { + vecRotPos.clear(); - std::vector* shapes = *shapepartsiter; - Ogre::Entity* theentity = *entitypartsiter; - - - handleShapes(shapes, theentity, base->getSkeleton()); - shapepartsiter++; - entitypartsiter++; - } - - } - + + /* + if(lBeastFoot) + handleShapes(lBeastFootShapes, lBeastFoot, base->getSkeleton()); + if(rBeastFoot) + handleShapes(rBeastFootShapes, rBeastFoot, base->getSkeleton()); + if(chest) + handleShapes(chestShapes, chest, base->getSkeleton()); + if(tail) + handleShapes(tailShapes, tail, base->getSkeleton()); + if(skirt) + handleShapes(skirtShapes, skirt, base->getSkeleton()); + if(lhand) + handleShapes(lhandShapes, lhand, base->getSkeleton()); + if(rhand) + handleShapes(rhandShapes, rhand, base->getSkeleton()); + */ } } +} \ No newline at end of file diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e524878cc..a95ce8526 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -6,26 +6,34 @@ #include #include #include +#include #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/environment.hpp" #include "components/nifogre/ogre_nif_loader.hpp" +#include "../mwworld/inventorystore.hpp" namespace MWRender{ class NpcAnimation: public Animation{ private: - + MWWorld::InventoryStore& inv; int mStateID; //Free Parts - Ogre::Entity* chest; std::vector* chestShapes; - Ogre::Entity* skirt; std::vector* skirtShapes; + std::pair*> chest; + std::pair*> skirt; + std::pair*> lhand; + std::pair*> rhand; + std::pair*> tail; + std::pair*> lBeastFoot; + std::pair*> rBeastFoot; + /*Ogre::Entity* skirt; std::vector* skirtShapes; Ogre::Entity* rhand; std::vector* rhandShapes; Ogre::Entity* lhand; std::vector* lhandShapes; Ogre::Entity* tail; std::vector* tailShapes; Ogre::Entity* lBeastFoot; std::vector* lBeastFootShapes; - Ogre::Entity* rBeastFoot; std::vector* rBeastFootShapes; + Ogre::Entity* rBeastFoot; std::vector* rBeastFootShapes;*/ //Bounded Parts Ogre::Entity* lclavicle; @@ -48,13 +56,14 @@ private: Ogre::Entity* rfoot; Ogre::Entity* hair; Ogre::Entity* head; + Ogre::SceneNode* insert; public: - NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend); + NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); virtual ~NpcAnimation(); Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); - void insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert); + std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); virtual void runAnimation(float timepassed); }; From 8c607870c066d5b13cd98f6a6ccd196f48acb465 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 11:26:54 +0200 Subject: [PATCH 079/185] test commit --- apps/openmw/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index df52faab1..f3b5c77bb 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -342,7 +342,7 @@ private: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { std::streambuf* old_rdbuf = std::cout.rdbuf (); - + std::cout << "Testing stuff in the new branch!"; int ret = 0; #if defined(_DEBUG) // Redirect cout to VS debug output when running in debug mode From d5b8d4ef49d72c8a9663129ac4dc11b7e7b82d90 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 11:30:17 +0200 Subject: [PATCH 080/185] Revert "test commit" This reverts commit 8c607870c066d5b13cd98f6a6ccd196f48acb465. reverting the test commit in the test branch --- apps/openmw/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index f3b5c77bb..df52faab1 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -342,7 +342,7 @@ private: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { std::streambuf* old_rdbuf = std::cout.rdbuf (); - std::cout << "Testing stuff in the new branch!"; + int ret = 0; #if defined(_DEBUG) // Redirect cout to VS debug output when running in debug mode From b1259ca15c71d9dcb95b6204ec4dbb106732b795 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 12:25:33 +0200 Subject: [PATCH 081/185] added a 'backend' for NPC/Player draw state --- apps/openmw/mwmechanics/drawstate.hpp | 11 +++++++++++ apps/openmw/mwmechanics/npcstats.hpp | 5 +++-- apps/openmw/mwworld/player.cpp | 7 +++++-- apps/openmw/mwworld/player.hpp | 8 +++++++- 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 apps/openmw/mwmechanics/drawstate.hpp diff --git a/apps/openmw/mwmechanics/drawstate.hpp b/apps/openmw/mwmechanics/drawstate.hpp new file mode 100644 index 000000000..3ea115d42 --- /dev/null +++ b/apps/openmw/mwmechanics/drawstate.hpp @@ -0,0 +1,11 @@ +#ifndef GAME_MWMECHANICS_DRAWSTATE_H +#define GAME_MWMECHANICS_DRAWSTATE_H + +enum DrawState +{ + DrawState_Weapon, + DrawState_Spell, + DrawState_Nothing +} + +#endif diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index aeb5f56d5..cd7c63f99 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -4,13 +4,13 @@ #include #include "stat.hpp" +#include "drawstate.hpp" namespace MWMechanics { /// \brief Additional stats for NPCs /// /// For non-NPC-specific stats, see the CreatureStats struct. - struct NpcStats { // NPCs other than the player can only have one faction. But for the sake of consistency @@ -24,9 +24,10 @@ namespace MWMechanics bool mRun; bool mSneak; bool mCombat; + DrawState mDrawState; NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), - mCombat (false) {} + mCombat (false) , mDrawState(DrawState::DrawState_Nothing) {} }; } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5bfb82138..a3e8e46c0 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -12,7 +12,7 @@ namespace MWWorld { Player::Player (MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world) : mCellStore (0), mRenderer (renderer), mWorld (world), mClass (0), - mAutoMove (false), mForwardBackward (0) + mAutoMove (false), mForwardBackward (0) , mDrawState(DrawState_Nothing) { mPlayer.base = player; mPlayer.ref.refID = "player"; @@ -47,7 +47,10 @@ namespace MWWorld delete mClass; mClass = new_class; } - + void Player::setDrawState(const DrawState& value) + { + mDrawState = value; + } void Player::setAutoMove (bool enable) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 01c71da43..f235140f8 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -8,6 +8,8 @@ #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" +#include "../mwmechanics/drawstate.hpp" + namespace MWRender { class Player; @@ -31,7 +33,7 @@ namespace MWWorld ESM::Class *mClass; bool mAutoMove; int mForwardBackward; - + DrawState mDrawState; public: Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); @@ -76,6 +78,8 @@ namespace MWWorld void setClass (const ESM::Class& class_); + void setDrawState(const DrawState& state); + std::string getName() const { return mName; @@ -106,6 +110,8 @@ namespace MWWorld return mAutoMove; } + DrawState getDrawState() { return mDrawState; } + void setAutoMove (bool enable); void setLeftRight (int value); From dcab6737e50aa122a4189f8083060d4bd352bdb0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Apr 2012 12:26:21 +0200 Subject: [PATCH 082/185] consider skills when auto equipping --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 41 ++++++++++++++++++++++---- apps/openmw/mwworld/inventorystore.hpp | 4 ++- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e68b99597..c948e00d5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -19,7 +19,7 @@ namespace MWMechanics { if (!paused) MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( - MWWorld::Class::get (ptr).getNpcStats (ptr)); + MWWorld::Class::get (ptr).getNpcStats (ptr), mEnvironment); } Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment), mDuration (0) {} diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 1fe76a0a8..650418201 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -4,6 +4,8 @@ #include #include +#include "../mwmechanics/npcstats.hpp" + #include "class.hpp" #include /// \todo remove after rendering is implemented @@ -94,7 +96,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } -void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) +void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats, + const Environment& environment) { TSlots slots; initSlots (slots); @@ -102,6 +105,7 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; + int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test, environment); std::pair, bool> itemsSlots = MWWorld::Class::get (*iter).getEquipmentSlots (*iter); @@ -109,15 +113,40 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { - if (slots.at (*iter2)!=end()) + bool use = false; + + if (slots.at (*iter2)==end()) + use = true; // slot was empty before -> skill all further checks + else { Ptr old = *slots.at (*iter2); - // check value - if (MWWorld::Class::get (old).getValue (old)>=MWWorld::Class::get (test).getValue (test)) + if (!use) + { + // check skill + int oldSkill = + MWWorld::Class::get (old).getEquipmentSkill (old, environment); + + if (testSkill!=-1 || oldSkill!=-1 || testSkill!=oldSkill) + { + if (stats.mSkill[oldSkill].getModified()>stats.mSkill[testSkill].getModified()) + continue; // rejected, because old item better matched the NPC's skills. + + if (stats.mSkill[oldSkill].getModified()= + MWWorld::Class::get (test).getValue (test)) + { + continue; + } + + use = true; } } diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 5eeaf570d..ca733b084 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -10,6 +10,8 @@ namespace MWMechanics namespace MWWorld { + struct Environment; + ///< \brief Variant of the ContainerStore for NPCs class InventoryStore : public ContainerStore { @@ -62,7 +64,7 @@ namespace MWWorld ContainerStoreIterator getSlot (int slot); - void autoEquip (const MWMechanics::NpcStats& stats); + void autoEquip (const MWMechanics::NpcStats& stats, const Environment& environment); ///< Auto equip items according to stats and item value. }; } From b4ee01e69113c2f2262099f15cab84aebb1e247e Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 12:26:59 +0200 Subject: [PATCH 083/185] missing file --- apps/openmw/mwinput/inputmanager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 3721d1043..7b0481f18 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -65,6 +65,8 @@ namespace MWInput A_QuickLoad, A_QuickMenu, A_GameMenu, + A_ToggleWeapon, + A_ToggleSpell, A_LAST // Marker for the last item }; From c1afd534fc292ee441cab56fbb4d1627f1166f78 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 12:37:59 +0200 Subject: [PATCH 084/185] all stuff added --- apps/openmw/mwinput/inputmanager.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 7b0481f18..4030eb902 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -88,6 +88,24 @@ namespace MWInput /* InputImpl Methods */ + void toggleSpell() + { + DrawState state = player.getDrawState(); + if(state == DrawState_Weapon || state == DrawState_Nothing) + player.setDrawState(DrawState_Spell); + else + player.setDrawState(DrawState_Nothing); + } + + void toggleWeapon() + { + DrawState state = player.getDrawState(); + if(state == DrawState_Spell || state == DrawState_Nothing) + player.setDrawState(DrawState_Weapon); + else + player.setDrawState(DrawState_Nothing); + } + void screenshot() { mEngine.screenshot(); @@ -199,7 +217,10 @@ namespace MWInput "Auto Move"); disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this), "Toggle Walk/Run"); - + disp->funcs.bind(A_ToggleWeapon,boost::bind(&InputImpl::toggleWeapon,this), + "Draw Weapon"); + disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), + "Ready hands"); // Add the exit listener ogre.getRoot()->addFrameListener(&exit); @@ -244,6 +265,8 @@ namespace MWInput disp->bind(A_AutoMove, KC_Z); disp->bind(A_ToggleSneak, KC_X); disp->bind(A_ToggleWalk, KC_C); + disp->bind(A_ToggleWeapon,KC_F); + disp->bind(A_ToggleSpell,KC_R); // Key bindings for polled keys // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. From ab2a1297b0a137cd2761c06210883835595d5bfd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Apr 2012 13:01:03 +0200 Subject: [PATCH 085/185] exclude player from auto equip --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c948e00d5..7d9f748d4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -17,7 +17,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { - if (!paused) + if (!paused && ptr.getRefData().getHandle()!="player") MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( MWWorld::Class::get (ptr).getNpcStats (ptr), mEnvironment); } From 15526d6110327a32d105c3212569e0033aed94b4 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 13:17:16 +0200 Subject: [PATCH 086/185] only fists support lacks --- apps/openmw/mwinput/inputmanager.cpp | 14 ++++++++++++++ apps/openmw/mwworld/player.cpp | 2 ++ 2 files changed, 16 insertions(+) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 4030eb902..bd27de029 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -92,18 +92,32 @@ namespace MWInput { DrawState state = player.getDrawState(); if(state == DrawState_Weapon || state == DrawState_Nothing) + { player.setDrawState(DrawState_Spell); + std::cout << "Player has now readied his hands for spellcasting!\n"; + } else + { player.setDrawState(DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n"; + } + } void toggleWeapon() { DrawState state = player.getDrawState(); if(state == DrawState_Spell || state == DrawState_Nothing) + { player.setDrawState(DrawState_Weapon); + std::cout << "Player is now drawing his weapon.\n"; + } else + { player.setDrawState(DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n"; + } + } void screenshot() diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index a3e8e46c0..b333d106a 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -47,10 +47,12 @@ namespace MWWorld delete mClass; mClass = new_class; } + void Player::setDrawState(const DrawState& value) { mDrawState = value; } + void Player::setAutoMove (bool enable) { MWWorld::Ptr ptr = getPlayer(); From c589cbd4ff12fcf98660e50ee9e318b742757e82 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 13:25:28 +0200 Subject: [PATCH 087/185] enum bug fix --- apps/openmw/mwmechanics/npcstats.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index cd7c63f99..7c5d37972 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -27,7 +27,7 @@ namespace MWMechanics DrawState mDrawState; NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), - mCombat (false) , mDrawState(DrawState::DrawState_Nothing) {} + mCombat (false) , mDrawState(DrawState_Nothing) {} }; } From 23cc1d17ca56950d8aeca6c9ea5d30dc49b01713 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 13:28:34 +0200 Subject: [PATCH 088/185] missing ; added --- apps/openmw/mwmechanics/drawstate.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/drawstate.hpp b/apps/openmw/mwmechanics/drawstate.hpp index 3ea115d42..ded25f8d5 100644 --- a/apps/openmw/mwmechanics/drawstate.hpp +++ b/apps/openmw/mwmechanics/drawstate.hpp @@ -3,9 +3,9 @@ enum DrawState { - DrawState_Weapon, - DrawState_Spell, - DrawState_Nothing -} + DrawState_Weapon = 0, + DrawState_Spell = 1, + DrawState_Nothing = 2, +}; #endif From 113bbfa253eac94ef1d46ed78928cd97538b8d94 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 14:37:36 +0200 Subject: [PATCH 089/185] removed the now unneccesary SG for transparent objects --- apps/openmw/mwrender/objects.cpp | 12 ++++++------ apps/openmw/mwrender/objects.hpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index a388d3163..b633330fa 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -144,7 +144,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) { Ogre::StaticGeometry* sg = 0; - if (transparent) +/* if (transparent) { if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end()) { @@ -155,7 +155,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) else sg = mStaticGeometryAlpha[ptr.getCell()]; } - else if (small) + else*/ if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { @@ -288,13 +288,13 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; } - if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end()) + /*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end()) { Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store]; mStaticGeometryAlpha.erase(store); mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; - } + }*/ if(mBounds.find(store) != mBounds.end()) mBounds.erase(store); @@ -312,11 +312,11 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell) Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; sg->build(); } - if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end()) + /*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end()) { Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell]; sg->build(); - } + }*/ } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 4326ce326..0c19f9f33 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -15,7 +15,7 @@ class Objects{ std::map mCellSceneNodes; std::map mStaticGeometry; std::map mStaticGeometrySmall; - std::map mStaticGeometryAlpha; + //std::map mStaticGeometryAlpha; std::map mBounds; std::vector mLights; Ogre::SceneNode* mMwRoot; From 8caa5ff9c494046fca7d1d07e4f8481d6b0d3931 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 15:03:09 +0200 Subject: [PATCH 090/185] fixed refraction and underwater distortion artifacts --- files/water/underwater.cg | 2 +- files/water/water.cg | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/files/water/underwater.cg b/files/water/underwater.cg index a734c316f..b853dd535 100644 --- a/files/water/underwater.cg +++ b/files/water/underwater.cg @@ -50,7 +50,7 @@ float4 main_fp (float2 iTexCoord : TEXCOORD0, { float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; - float depth = tex2D(DepthMap, iTexCoord).r * far; + float depth = tex2D(DepthMap, iTexCoord + normal.xy * 0.015).r * far; depth = saturate(depth / 2000.f); float4 color = tex2D(RT, iTexCoord + normal.xy * 0.015) + diff --git a/files/water/water.cg b/files/water/water.cg index bbd42874b..7c7ec0780 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -62,7 +62,6 @@ void main_fp float depthTex = tex2D(depthMap, screenCoords).r; float depth1 = depthTex * far - iDepth; depth1 = saturate(depth1 / 500.f); - depth1 = (depthTex == 0 ? 1 : depth1); // Simple wave effect. to be replaced by something better float2 uv1 = iUv + time * float2(0.5, 0); @@ -74,7 +73,20 @@ void main_fp normal = 2*normal - 1; float2 screenCoords_reflect = screenCoords + normal.yx * 0.05; - float2 screenCoords_refract = screenCoords + normal.yx * 0.1 * depth1; + float2 screenCoords_refract = screenCoords + normal.yx * 0.05 * depth1; + + // Sample depth again with the refracted coordinates + depthTex = tex2D(depthMap, screenCoords_refract).r; + float depth2 = (depthTex * far - iDepth) / 500.f; + depth2 = (depthTex == 0 ? 1 : depth2); + // if depth2 is less than 0, this means we would refract something which is above water, + // which we don't want to - so in that case, don't refract + if (depth2 < 0.25) // delta due to inaccuracies + { + screenCoords_refract = screenCoords; + depth2 = depth1; + } + depth2 = saturate(depth2); float4 reflection = tex2D(reflectionMap, screenCoords_reflect); float4 refraction = tex2D(refractionMap, screenCoords_refract); @@ -93,7 +105,7 @@ void main_fp float3 halfVector = normalize(iEyeVector + lightDir); float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64); - float opacity = depth1 * saturate(reflectionFactor + specular); + float opacity = depth2 * saturate(reflectionFactor + specular); opacity *= (1-isUnderwater); reflection.xyz += lightSpecularColour0.xyz * specular; From 17eb68e4bcbfe066d37e51a2baf0a2bf9a588c7b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 15:52:43 +0200 Subject: [PATCH 091/185] disable "reflect statics" by default because it performs not so well right now --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e3a5ceb7b..8209580d7 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -63,7 +63,7 @@ rtt size = 512 reflect terrain = true -reflect statics = true +reflect statics = false reflect small statics = false From fbfc6e0966be9b13083f86046e79db257c1ef084 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 16:06:47 +0200 Subject: [PATCH 092/185] enabled new water by default --- files/settings-default.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 8209580d7..efe03972b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -57,7 +57,7 @@ num lights = 8 [Water] # Enable this to get fancy-looking water with reflections and refractions # All the settings below have no effect if this is false -shader = false +shader = true rtt size = 512 From a5c6207fe76e710e30f8db6ed65ce799e2e678ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 17:44:00 +0200 Subject: [PATCH 093/185] add setting to disable the underwater effect --- apps/openmw/mwrender/water.cpp | 18 +++++------------- apps/openmw/mwrender/water.hpp | 3 +-- files/settings-default.cfg | 3 +++ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 615a24a76..7981def0b 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -10,7 +10,7 @@ namespace MWRender Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), - mIsUnderwater(false), mReflectDistance(0), mVisibilityFlags(0), mOldCameraFarClip(0), + mIsUnderwater(false), mVisibilityFlags(0), mReflectionTarget(0), mActive(1) { mSky = sky; @@ -38,7 +38,6 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + RV_Sky; - mReflectDistance = Settings::Manager::getInt("reflect distance", "Water"); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); mWaterNode->setPosition(0, mTop, 0); @@ -73,6 +72,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : createMaterial(); mWater->setMaterial(mMaterial); + + mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); } void Water::setActive(bool active) @@ -120,9 +121,7 @@ void Water::checkUnderwater(float y) if (!mActive) return; if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { - try { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); - } catch(...) {} + CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); // tell the shader we are not underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); @@ -139,9 +138,8 @@ void Water::checkUnderwater(float y) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { - try { + if (mUnderwaterEffect) CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true); - } catch(...) {} // tell the shader we are underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); @@ -164,10 +162,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { - //mOldCameraFarClip = mCamera->getFarClipDistance(); - //if (mReflectDistance != 0) - // mCamera->setFarClipDistance(mReflectDistance); - if (evt.source == mReflectionTarget) { mWater->setVisible(false); @@ -189,8 +183,6 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mWater->setVisible(true); - //mCamera->setFarClipDistance(mOldCameraFarClip); - if (evt.source == mReflectionTarget) { mSky->resetSkyPosition(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index b5aa29a5b..0e23f5b0c 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -41,9 +41,8 @@ namespace MWRender { Ogre::RenderTarget* mReflectionTarget; + bool mUnderwaterEffect; int mVisibilityFlags; - int mReflectDistance; - int mOldCameraFarClip; public: Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6b037c06a..4b86cba92 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -71,6 +71,9 @@ reflect actors = true reflect misc = false +# Enable underwater effect. It is not resource intensive, so only disable it if you have problems. +underwater effect = true + [Sound] # Device name. Blank means default device = From 0b2dab0b5dca85d548bb29305456db3a845c31d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 18:17:52 +0200 Subject: [PATCH 094/185] disable water fog due to some issues --- files/water/water.cg | 4 ++-- files/water/water.material | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/files/water/water.cg b/files/water/water.cg index 7c7ec0780..bf6d04c5c 100644 --- a/files/water/water.cg +++ b/files/water/water.cg @@ -116,6 +116,6 @@ void main_fp oColor.xyz = lerp(oColor.xyz, float3(0, 0.65, 0.65), saturate(isUnderwater * (iDepth / 2000.f))); // underwater fog // add fog - float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); - oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); + //float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); + //oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); } diff --git a/files/water/water.material b/files/water/water.material index 1b8573c4a..7ce6e7ba2 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -59,8 +59,8 @@ material Water fragment_program_ref Water_FP { param_named_auto time time 0.1 - param_named_auto fogColour fog_colour - param_named_auto fogParams fog_params + //param_named_auto fogColour fog_colour + //param_named_auto fogParams fog_params param_named_auto renderTargetFlipping render_target_flipping param_named_auto far far_clip_distance param_named_auto lightPosObjSpace0 light_position_object_space 0 From 00b8ce6b355ed71253e0760456fcf9465ec682ca Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 18:22:41 +0200 Subject: [PATCH 095/185] Fix linker error in windows. --- apps/openmw/mwworld/inventorystore.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index ca733b084..60b89b0b4 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -10,7 +10,7 @@ namespace MWMechanics namespace MWWorld { - struct Environment; + class Environment; ///< \brief Variant of the ContainerStore for NPCs class InventoryStore : public ContainerStore From 9893e4b38484cb9806af407a9f52d8a536542687 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 19:43:04 +0200 Subject: [PATCH 096/185] made player respect NpcStats for mDrawState --- apps/openmw/mwworld/player.cpp | 12 ++++++++++-- apps/openmw/mwworld/player.hpp | 5 ++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b333d106a..d24780ec1 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -4,6 +4,7 @@ #include "../mwrender/player.hpp" #include "../mwmechanics/movement.hpp" +#include "../mwmechanics/npcstats.hpp" #include "world.hpp" #include "class.hpp" @@ -12,7 +13,7 @@ namespace MWWorld { Player::Player (MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world) : mCellStore (0), mRenderer (renderer), mWorld (world), mClass (0), - mAutoMove (false), mForwardBackward (0) , mDrawState(DrawState_Nothing) + mAutoMove (false), mForwardBackward (0) { mPlayer.base = player; mPlayer.ref.refID = "player"; @@ -50,7 +51,8 @@ namespace MWWorld void Player::setDrawState(const DrawState& value) { - mDrawState = value; + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState = value; } void Player::setAutoMove (bool enable) @@ -94,4 +96,10 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } + + DrawState Player::getDrawState() + { + MWWorld::Ptr ptr = getPlayer(); + return MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState; + } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index f235140f8..8dcd9fcc6 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -20,7 +20,7 @@ namespace MWWorld class World; /// \brief NPC object representing the player and additional player data - class Player + class Player { ESMS::LiveCellRef mPlayer; MWWorld::Ptr::CellStore *mCellStore; @@ -33,7 +33,6 @@ namespace MWWorld ESM::Class *mClass; bool mAutoMove; int mForwardBackward; - DrawState mDrawState; public: Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); @@ -110,7 +109,7 @@ namespace MWWorld return mAutoMove; } - DrawState getDrawState() { return mDrawState; } + DrawState getDrawState(); void setAutoMove (bool enable); From db928dcb2ffae1a12240d9dc0567c677d3d5df57 Mon Sep 17 00:00:00 2001 From: Aleksandar Jovanov Date: Sun, 8 Apr 2012 19:44:11 +0200 Subject: [PATCH 097/185] put an opening bracket on a new line --- apps/openmw/mwworld/class.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 9d766909f..ae12a2ab9 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -26,7 +26,9 @@ namespace MWWorld { } - void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const{ + + void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + { } From aa8208efb97ad70f8559ad316efb7755e2bb1516 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 8 Apr 2012 22:18:56 +0200 Subject: [PATCH 098/185] changed compositor to be compatible with Ogre 1.8RC --- files/gbuffer/gbuffer.compositor | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index 6ca35df87..316003af6 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -11,8 +11,11 @@ compositor gbuffer input none pass clear { - // make sure to set this to the viewport background color from outside - colour_value 0 0 0 1 + clear + { + // make sure to set this to the viewport background color from outside + colour_value 0 0 0 1 + } } pass render_scene { @@ -56,8 +59,11 @@ compositor gbufferFinalizer shadows off pass clear { - buffers colour - colour_value 0 0 0 0 + clear + { + buffers colour + colour_value 0 0 0 0 + } } pass render_quad { @@ -75,6 +81,9 @@ compositor gbufferFinalizer input none pass clear { + clear + { + } } pass render_quad { From 6bdfdf379b46c7d2d009c5f1fb691d094597357f Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 8 Apr 2012 17:27:56 -0400 Subject: [PATCH 099/185] Trying iterators --- apps/openmw/mwrender/npcanimation.cpp | 79 +++++++++++++++++---------- apps/openmw/mwrender/npcanimation.hpp | 10 +++- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 30c28bb79..ea00919c6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -11,12 +11,18 @@ NpcAnimation::~NpcAnimation(){ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv){ +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ ESMS::LiveCellRef *ref = ptr.get(); Ogre::Entity* blank = 0; std::vector* blankshape = 0; chest = std::make_pair(blank, blankshape); + tail = std::make_pair(blank, blankshape); + lBeastFoot = std::make_pair(blank, blankshape); + rBeastFoot = std::make_pair(blank, blankshape); + rhand = std::make_pair(blank, blankshape); + lhand = std::make_pair(blank, blankshape); + skirt = std::make_pair(blank, blankshape); //Part selection on last character of the file string // " Tri Chest // * Tri Tail @@ -35,18 +41,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O // vector = Ogre::Vector3(1,1,-1); - std::string hairID = ref->base->hair; - std::string headID = ref->base->head; - std::string npcName = ref->base->name; + hairID = ref->base->hair; + headID = ref->base->head; + npcName = ref->base->name; //ESMStore::Races r = const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); - std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); + bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2); bool female = tolower(secondtolast) == 'f'; std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; + isBeast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; /*std::cout << "Race: " << ref->base->race ; if(female){ @@ -59,7 +65,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O std::string smodel = "meshes\\base_anim.nif"; - if(beast) + if(isBeast) smodel = "meshes\\base_animkna.nif"; insert = ptr.getRefData().getBaseNode(); @@ -92,11 +98,26 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O 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\\" + + updateParts(); + +} + +void NpcAnimation::updateParts(){ + std::string headModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; std::string hairModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; + + //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + + robe = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); + if(robe == inv.end()) + std::cout << "No part\n"; + else + std::cout << "yes part\n"; + + const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); const ESM::BodyPart *groinpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin"); @@ -216,9 +237,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O lBeastFoot = insertFreePart("meshes\\" + feetpart->model,"::"); rBeastFoot = insertFreePart("meshes\\" + feetpart->model,":<"); } - //originalpos = insert->_getWorldAABB().getCenter(); - //originalscenenode = insert->getPosition(); - + //originalpos = insert->_getWorl } Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ @@ -252,8 +271,10 @@ std::pair*> NpcAnimation::insert void NpcAnimation::runAnimation(float timepassed){ - - mStateID = inv.getStateId(); + if(mStateID != inv.getStateId()){ + mStateID = inv.getStateId(); + updateParts(); + } //1. Add the amount of time passed to time @@ -278,22 +299,22 @@ void NpcAnimation::runAnimation(float timepassed){ vecRotPos.clear(); - /* - if(lBeastFoot) - handleShapes(lBeastFootShapes, lBeastFoot, base->getSkeleton()); - if(rBeastFoot) - handleShapes(rBeastFootShapes, rBeastFoot, base->getSkeleton()); - if(chest) - handleShapes(chestShapes, chest, base->getSkeleton()); - if(tail) - handleShapes(tailShapes, tail, base->getSkeleton()); - if(skirt) - handleShapes(skirtShapes, skirt, base->getSkeleton()); - if(lhand) - handleShapes(lhandShapes, lhand, base->getSkeleton()); - if(rhand) - handleShapes(rhandShapes, rhand, base->getSkeleton()); - */ + + if(lBeastFoot.first) + handleShapes(lBeastFoot.second, lBeastFoot.first, base->getSkeleton()); + if(rBeastFoot.first) + handleShapes(rBeastFoot.second, rBeastFoot.first, base->getSkeleton()); + if(chest.first) + handleShapes(chest.second, chest.first, base->getSkeleton()); + if(tail.first) + handleShapes(tail.second, tail.first, base->getSkeleton()); + if(skirt.first) + handleShapes(skirt.second, skirt.first, base->getSkeleton()); + if(lhand.first) + handleShapes(lhand.second, lhand.first, base->getSkeleton()); + if(rhand.first) + handleShapes(rhand.second, rhand.first, base->getSkeleton()); + } } } \ No newline at end of file diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a95ce8526..aae97db2a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -13,6 +13,8 @@ #include "../mwworld/environment.hpp" #include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwclass/npc.hpp" +#include "../mwworld/containerstore.hpp" namespace MWRender{ @@ -57,7 +59,12 @@ private: Ogre::Entity* hair; Ogre::Entity* head; Ogre::SceneNode* insert; - + bool isBeast; + std::string headID; + std::string hairID; + std::string npcName; + std::string bodyRaceID; + MWWorld::ContainerStoreIterator robe; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); @@ -65,6 +72,7 @@ private: Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); virtual void runAnimation(float timepassed); + void updateParts(); }; } From 0aecb0ed5c553d3c818f84a480fe655da59dae5a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 8 Apr 2012 23:44:40 +0200 Subject: [PATCH 100/185] cmake fix --- apps/openmw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2342882e0..a8ae0bd49 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -55,7 +55,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanager stat creaturestats magiceffects movement actors + mechanicsmanager stat creaturestats magiceffects movement actors drawstate ) # Main executable From 1df7be7feedbe112b229a56282d620d17244fc6b Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Apr 2012 00:10:42 +0200 Subject: [PATCH 101/185] - fixes to texture filtering setting - add a sensible warning to settings-default.cfg, since there have been some confusions with it --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- files/settings-default.cfg | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8d84af98f..aadc92369 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -41,10 +41,11 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const std::string filter = Settings::Manager::getString("texture filtering", "General"); if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; - else /* if (filter == "bilinear") */ tfo = TFO_BILINEAR; + else if (filter == "bilinear") tfo = TFO_BILINEAR; + else if (filter == "none") tfo = TFO_NONE; MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); - MaterialManager::getSingleton().setDefaultAnisotropy(Settings::Manager::getInt("anisotropy", "General")); + MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4b86cba92..d5a8bdfd4 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1,8 +1,12 @@ +# WARNING: Editing this file might have no effect, as these +# settings are overwritten by your user settings file. + [General] # Camera field of view field of view = 55 # Texture filtering mode. valid values: +# none # anisotropic # bilinear # trilinear From 80afcb2eac55b8c9b13c660c858cadbe6b7e8586 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 8 Apr 2012 20:44:44 -0400 Subject: [PATCH 102/185] small change --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f7877d2ad..4b3c23e64 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -295,7 +295,7 @@ void NpcAnimation::runAnimation(float timepassed){ if(mStateID != inv.getStateId()){ std::cout << "StateID" < Date: Mon, 9 Apr 2012 00:51:10 -0400 Subject: [PATCH 103/185] one more change --- apps/openmw/mwrender/npcanimation.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4b3c23e64..8097afdbf 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -134,8 +134,10 @@ void NpcAnimation::updateParts(){ //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - //MWWorld::ContainerStoreIterator robe = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); - //if(robe == inv.end()) + MWWorld::ContainerStoreIterator robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + + + // ; @@ -295,6 +297,7 @@ void NpcAnimation::runAnimation(float timepassed){ if(mStateID != inv.getStateId()){ std::cout << "StateID" < Date: Mon, 9 Apr 2012 13:24:19 +0200 Subject: [PATCH 104/185] pcRaiseRank works. Player can now join factions. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 22 ++++++---- apps/openmw/mwscript/docs/vmformat.txt | 5 ++- apps/openmw/mwscript/statsextensions.cpp | 47 +++++++++++++++++----- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index cd7be5031..b36c9d998 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -181,7 +181,17 @@ namespace MWDialogue break; case 46://Same faction - if(!selectCompare(comp,0,select.i)) return false; + { + MWMechanics::NpcStats PCstats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); + int sameFaction = 0; + if(!NPCstats.mFactionRank.empty()) + { + std::string NPCFaction = NPCstats.mFactionRank.begin()->first; + if(PCstats.mFactionRank.find(NPCFaction) != PCstats.mFactionRank.end()) sameFaction = 1; + } + if(!selectCompare(comp,sameFaction,select.i)) return false; + } break; case 48://Detected @@ -193,7 +203,6 @@ namespace MWDialogue break; case 50://choice - if(choice) { if(!selectCompare(comp,mChoice,select.i)) return false; @@ -447,9 +456,6 @@ namespace MWDialogue if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) return false; - //PC Faction - if(!info.pcFaction.empty()) return false; - //NPC race if (!info.race.empty()) { @@ -495,8 +501,8 @@ namespace MWDialogue // TODO check player faction if(!info.pcFaction.empty()) { - MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); - std::map::iterator it = stats.mFactionRank.find(info.npcFaction); + MWMechanics::NpcStats stats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + std::map::iterator it = stats.mFactionRank.find(info.pcFaction); if(it!=stats.mFactionRank.end()) { //check rank @@ -816,7 +822,7 @@ namespace MWDialogue std::string DialogueManager::getFaction() { std::string factionID(""); - MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor); if(stats.mFactionRank.empty()) { std::cout << "No faction for this actor!"; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 27b426d0e..2b20b973c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -24,7 +24,8 @@ op 0x20007: PlayAnim, explicit reference op 0x20008: LoopAnim op 0x20009: LoopAnim, explicit reference op 0x2000a: Choice -opcodes 0x2000b-0x3ffff unused +op 0x2000b: PCRaiseRank +opcodes 0x2000c-0x3ffff unused Segment 4: (not implemented yet) @@ -127,5 +128,5 @@ op 0x2000141: GetWaterLevel op 0x2000142: SetWaterLevel op 0x2000143: ModWaterLevel op 0x2000144: ToggleWater, twa -op 0x2000145: PCRaiseRank +op 0x2000145: ModDisposition opcodes 0x2000146-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index be31321e9..05db10301 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -299,27 +299,54 @@ namespace MWScript } }; - class OpPCRaiseRank : public Interpreter::Opcode0 + class OpPCRaiseRank : public Interpreter::Opcode1 { public: - virtual void execute (Interpreter::Runtime& runtime) + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { + std::cout << "arg0:" << arg0<< std::endl; std::cout << "try to rais rank..."; + std::string factionID = ""; MWScript::InterpreterContext& context = static_cast (runtime.getContext()); - - std::string factionID = context.getEnvironment().mDialogueManager->getFaction(); + if(arg0==0) + { + std::cout << "slurpppp"; + factionID = context.getEnvironment().mDialogueManager->getFaction(); + } + else + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } if(factionID != "") { std::cout << "raiserank!!!!!"; MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + { + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + } + else + { + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] +1; + } } std::cout << std::endl; } }; + class OpModDisposition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -351,7 +378,8 @@ namespace MWScript const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; //const int opcodePCJoinFaction = 0x2000141; - const int opcodePCRaiseRank = 0x2000145; + const int opcodePCRaiseRank = 0x2000b; + const int opcodeModDisposition = 0x2000145; void registerExtensions (Compiler::Extensions& extensions) { @@ -424,8 +452,8 @@ namespace MWScript opcodeModSkill+i, opcodeModSkillExplicit+i); } //extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); - std::cout << "rgister raiserank"; - extensions.registerInstruction("pcraiserank","",opcodePCRaiseRank); + extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); + extensions.registerInstruction("moddisposition","l",opcodeModDisposition); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -483,7 +511,8 @@ namespace MWScript } //interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); - interpreter.installSegment5(opcodePCRaiseRank,new OpPCRaiseRank); + interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); + interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); } } } From 45d11eaf144a160d8a3b3a2fb83e0a1b491a2324 Mon Sep 17 00:00:00 2001 From: gugus Date: Mon, 9 Apr 2012 14:23:12 +0200 Subject: [PATCH 105/185] fixed a bug in the dialogue manager. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index b36c9d998..5dded07b0 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -112,16 +112,15 @@ namespace switch (world.getGlobalVariableType (name)) { case 's': - - return selectCompare (comp, value, world.getGlobalVariable (name).mShort); + return selectCompare (comp, world.getGlobalVariable (name).mShort, value); case 'l': - return selectCompare (comp, value, world.getGlobalVariable (name).mLong); + return selectCompare (comp, world.getGlobalVariable (name).mLong, value); case 'f': - return selectCompare (comp, value, world.getGlobalVariable (name).mFloat); + return selectCompare (comp, world.getGlobalVariable (name).mFloat, value); case ' ': @@ -282,7 +281,7 @@ namespace MWDialogue { case '1': // function - return true; // TODO implement functions + return true; // Done elsewhere. case '2': // global From aa8418634f8f776a09e19bf141e322505b26ad1f Mon Sep 17 00:00:00 2001 From: gugus Date: Mon, 9 Apr 2012 14:26:53 +0200 Subject: [PATCH 106/185] add PCLowerRank script instruction --- apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/statsextensions.cpp | 43 +++++++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 2b20b973c..9a5cf8525 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -25,7 +25,8 @@ op 0x20008: LoopAnim op 0x20009: LoopAnim, explicit reference op 0x2000a: Choice op 0x2000b: PCRaiseRank -opcodes 0x2000c-0x3ffff unused +op 0x2000c: PCLowerRank +opcodes 0x2000d-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 05db10301..176f139aa 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -305,14 +305,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - std::cout << "arg0:" << arg0<< std::endl; - std::cout << "try to rais rank..."; std::string factionID = ""; MWScript::InterpreterContext& context = static_cast (runtime.getContext()); if(arg0==0) { - std::cout << "slurpppp"; factionID = context.getEnvironment().mDialogueManager->getFaction(); } else @@ -322,7 +319,6 @@ namespace MWScript } if(factionID != "") { - std::cout << "raiserank!!!!!"; MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { @@ -336,7 +332,41 @@ namespace MWScript std::cout << std::endl; } }; - + + class OpPCLowerRank : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + std::string factionID = ""; + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + if(arg0==0) + { + factionID = context.getEnvironment().mDialogueManager->getFaction(); + } + else + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + if(factionID != "") + { + MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + { + //do nothing, the player is not in the faction... Throw an exeption? + } + else + { + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] -1; + } + } + std::cout << std::endl; + } + }; + class OpModDisposition : public Interpreter::Opcode0 { public: @@ -379,6 +409,7 @@ namespace MWScript const int opcodeModSkillExplicit = 0x2000115; //const int opcodePCJoinFaction = 0x2000141; const int opcodePCRaiseRank = 0x2000b; + const int opcodePCLowerRank = 0x2000c; const int opcodeModDisposition = 0x2000145; void registerExtensions (Compiler::Extensions& extensions) @@ -453,6 +484,7 @@ namespace MWScript } //extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); + extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); extensions.registerInstruction("moddisposition","l",opcodeModDisposition); } @@ -512,6 +544,7 @@ namespace MWScript //interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); + interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); } } From 6ca212b9e96280cbb671d22b44795ecdc64a6198 Mon Sep 17 00:00:00 2001 From: gugus Date: Mon, 9 Apr 2012 14:30:42 +0200 Subject: [PATCH 107/185] script instruction: PCJoinFaction --- apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/statsextensions.cpp | 35 ++++++++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 9a5cf8525..30b9f97e7 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -26,7 +26,8 @@ op 0x20009: LoopAnim, explicit reference op 0x2000a: Choice op 0x2000b: PCRaiseRank op 0x2000c: PCLowerRank -opcodes 0x2000d-0x3ffff unused +op x20000d: PCJoinFaction +opcodes 0x2000e-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 176f139aa..5b64ee239 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -284,18 +284,36 @@ namespace MWScript } }; - class OpPCJoinFaction : public Interpreter::Opcode0 + class OpPCJoinFaction : public Interpreter::Opcode1 { public: - virtual void execute (Interpreter::Runtime& runtime) + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { + std::string factionID = ""; MWScript::InterpreterContext& context = static_cast (runtime.getContext()); - - std::string factionID = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - context.getEnvironment().mWorld->getPlayer().addFaction(factionID); + if(arg0==0) + { + factionID = context.getEnvironment().mDialogueManager->getFaction(); + } + else + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + if(factionID != "") + { + MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + { + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + } + else + { + //the player is already in the faction... Throw an exeption? + } + } } }; @@ -329,7 +347,6 @@ namespace MWScript MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] +1; } } - std::cout << std::endl; } }; @@ -363,7 +380,6 @@ namespace MWScript MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] -1; } } - std::cout << std::endl; } }; @@ -410,6 +426,7 @@ namespace MWScript //const int opcodePCJoinFaction = 0x2000141; const int opcodePCRaiseRank = 0x2000b; const int opcodePCLowerRank = 0x2000c; + const int opcodePCJoinFaction = 0x2000d; const int opcodeModDisposition = 0x2000145; void registerExtensions (Compiler::Extensions& extensions) @@ -485,6 +502,7 @@ namespace MWScript //extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); + extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); extensions.registerInstruction("moddisposition","l",opcodeModDisposition); } @@ -545,6 +563,7 @@ namespace MWScript //interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); + interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); } } From dd9a88cee266f4e91bd77312b3b083c9c9a47ad7 Mon Sep 17 00:00:00 2001 From: gugus Date: Mon, 9 Apr 2012 14:32:07 +0200 Subject: [PATCH 108/185] clean up --- apps/openmw/mwscript/statsextensions.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 5b64ee239..27983eca8 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -423,7 +423,7 @@ namespace MWScript const int opcodeSetSkillExplicit = 0x20000df; const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; - //const int opcodePCJoinFaction = 0x2000141; + const int opcodePCRaiseRank = 0x2000b; const int opcodePCLowerRank = 0x2000c; const int opcodePCJoinFaction = 0x2000d; @@ -499,7 +499,6 @@ namespace MWScript extensions.registerInstruction (mod + skills[i], "l", opcodeModSkill+i, opcodeModSkillExplicit+i); } - //extensions.registerInstruction("PCJoinFaction","S",opcodePCJoinFaction); extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); @@ -560,7 +559,6 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } - //interpreter.installSegment5(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); From 944654f2637c68231583c636f064c6308067aa7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Apr 2012 15:20:57 +0200 Subject: [PATCH 109/185] image rotating function --- CMakeLists.txt | 1 + libs/openengine/ogre/imagerotate.cpp | 74 ++++++++++++++++++++++++++++ libs/openengine/ogre/imagerotate.hpp | 27 ++++++++++ 3 files changed, 102 insertions(+) create mode 100644 libs/openengine/ogre/imagerotate.cpp create mode 100644 libs/openengine/ogre/imagerotate.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b87e3544..148386432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/mouselook.cpp ${LIBDIR}/openengine/ogre/fader.cpp + ${LIBDIR}/openengine/ogre/imagerotate.cpp ) set(OENGINE_GUI ${LIBDIR}/openengine/gui/events.cpp diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp new file mode 100644 index 000000000..a6304277e --- /dev/null +++ b/libs/openengine/ogre/imagerotate.cpp @@ -0,0 +1,74 @@ +#include "imagerotate.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Ogre; +using namespace OEngine::Render; + +void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) +{ + Root* root = Ogre::Root::getSingletonPtr(); + + SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); + Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); + + MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); + Degree deg(angle); + tus->setTextureRotate(Radian(deg.valueRadians())); + tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); + tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); + + Rectangle2D* rect = new Rectangle2D(true); + rect->setCorners(-1.0, 1.0, 1.0, -1.0); + rect->setMaterial("ImageRotateMaterial"); + // Render the background before everything else + rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); + + // Use infinite AAB to always stay visible + AxisAlignedBox aabInf; + aabInf.setInfinite(); + rect->setBoundingBox(aabInf); + + // Attach background to the scene + SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(rect); + + // retrieve image width and height + TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); + unsigned int width = sourceTexture->getWidth(); + unsigned int height = sourceTexture->getHeight(); + + TexturePtr destTexture = TextureManager::getSingleton().createManual( + "ImageRotateDestTexture", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_R8G8B8, + TU_RENDERTARGET); + + RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(camera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + + rtt->update(); + rtt->writeContentsToFile(destImage); + + // remove all the junk we've created + TextureManager::getSingleton().remove("ImageRotateDestTexture"); + MaterialManager::getSingleton().remove("ImageRotateMaterial"); + root->destroySceneManager(sceneMgr); + delete rect; +} diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp new file mode 100644 index 000000000..85363d71f --- /dev/null +++ b/libs/openengine/ogre/imagerotate.hpp @@ -0,0 +1,27 @@ +#ifndef OENGINE_OGRE_IMAGEROTATE_HPP +#define OENGINE_OGRE_IMAGEROTATE_HPP + +#include + +namespace OEngine +{ +namespace Render +{ + + /// Rotate an image by certain degrees and save as file, uses the GPU + /// Make sure Ogre Root is initialised before calling + class ImageRotate + { + public: + /** + * @param source image (file name - has to exist in an resource group) + * @param destination image (absolute file path) + * @param angle in degrees to turn + */ + static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); + }; + +} +} + +#endif From 33f360f52f363e67a65b1432a33442d9bfc0a303 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Apr 2012 15:36:51 +0200 Subject: [PATCH 110/185] transparency fix --- libs/openengine/ogre/imagerotate.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index a6304277e..166a1d3c6 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -54,7 +54,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest TEX_TYPE_2D, width, height, 0, - PF_R8G8B8, + PF_A8R8G8B8, TU_RENDERTARGET); RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); @@ -62,6 +62,8 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest Viewport* vp = rtt->addViewport(camera); vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0,0,0,0)); + vp->setClearEveryFrame(true, FBT_DEPTH); rtt->update(); rtt->writeContentsToFile(destImage); From 344641e5748d5cb12bcddebd4706a585c73ebbd8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Apr 2012 13:38:17 +0200 Subject: [PATCH 111/185] updated developer list in readme file --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 17806172f..e1c24ab52 100644 --- a/readme.txt +++ b/readme.txt @@ -95,6 +95,7 @@ Allowed options: CREDITS Current Developers: +Aleksandar Jovanov Alexander “Ace” Olofsson athile BrotherBrick From 2a4fcf42a3a8af3314a0c87deb2d719944482a73 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Apr 2012 18:53:13 +0200 Subject: [PATCH 112/185] basic shadows --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/localmap.cpp | 4 +- apps/openmw/mwrender/objects.cpp | 2 + apps/openmw/mwrender/occlusionquery.cpp | 3 + apps/openmw/mwrender/renderingmanager.cpp | 33 ++- apps/openmw/mwrender/renderingmanager.hpp | 15 +- apps/openmw/mwrender/shaderhelper.cpp | 308 ++++++++++++++++++++++ apps/openmw/mwrender/shaderhelper.hpp | 29 ++ apps/openmw/mwrender/shadows.cpp | 175 ++++++++++++ apps/openmw/mwrender/shadows.hpp | 39 +++ apps/openmw/mwrender/sky.cpp | 10 + apps/openmw/mwrender/terrain.cpp | 21 +- apps/openmw/mwrender/terrain.hpp | 3 +- apps/openmw/mwrender/terrainmaterial.cpp | 110 ++++---- apps/openmw/mwrender/terrainmaterial.hpp | 5 + apps/openmw/mwrender/water.cpp | 75 +++++- apps/openmw/mwrender/water.hpp | 2 + components/nifogre/ogre_nif_loader.cpp | 181 +++---------- files/CMakeLists.txt | 3 + files/settings-default.cfg | 31 ++- files/shadows/depthshadowcaster.cg | 51 ++++ files/shadows/depthshadowcaster.material | 67 +++++ files/water/water.material | 2 +- 24 files changed, 953 insertions(+), 219 deletions(-) create mode 100644 apps/openmw/mwrender/shaderhelper.cpp create mode 100644 apps/openmw/mwrender/shaderhelper.hpp create mode 100644 apps/openmw/mwrender/shadows.cpp create mode 100644 apps/openmw/mwrender/shadows.hpp create mode 100644 files/shadows/depthshadowcaster.cg create mode 100644 files/shadows/depthshadowcaster.material diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a8ae0bd49..6a65c0e14 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects - renderinginterface localmap occlusionquery terrain terrainmaterial water + renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper ) add_openmw_dir (mwinput diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 259733600..1adcf8dca 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -362,6 +362,7 @@ void OMW::Engine::go() addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "gbuffer"); + addResourcesDirectory(mResDir / "shadows"); // Create the window mOgre->createWindow("OpenMW"); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index cb3c0a204..2cc233a01 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -225,7 +225,9 @@ void LocalMap::render(const float x, const float y, vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setVisibilityMask(RV_Map); - vp->setMaterialScheme("Map"); + + // use fallback techniques without shadows and without mrt + vp->setMaterialScheme("Fallback"); rtt->update(); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index b633330fa..eb7e440cb 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -193,6 +193,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); + sg->setCastShadows(true); + sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); mRenderer.getScene()->destroyEntity(ent); diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index d789b8c4e..80b804dce 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -60,6 +60,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); + mBBQueryTotal->setCastShadows(false); mBBQueryTotal->setDefaultDimensions(150, 150); mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->setMaterialName("QueryTotalPixels"); @@ -67,6 +68,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBNodeReal->attachObject(mBBQueryTotal); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); + mBBQueryVisible->setCastShadows(false); mBBQueryVisible->setDefaultDimensions(150, 150); mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->setMaterialName("QueryVisiblePixels"); @@ -75,6 +77,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); /// \todo ideally this should occupy exactly 1 pixel on the screen + mBBQuerySingleObject->setCastShadows(false); mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aadc92369..ee60407b2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -14,6 +14,10 @@ #include #include +#include "shadows.hpp" +#include "shaderhelper.hpp" +#include "localmap.hpp" +#include "water.hpp" using namespace MWRender; using namespace Ogre; @@ -21,11 +25,9 @@ using namespace Ogre; namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment) - :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0) + :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mSunEnabled(0) { mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); - mTerrainManager = new TerrainManager(mRendering.getScene(), - environment); mWater = 0; @@ -86,6 +88,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode(); cameraPitchNode->attachObject(mRendering.getCamera()); + mShadows = new Shadows(&mRendering); + mShaderHelper = new ShaderHelper(this); + + mTerrainManager = new TerrainManager(mRendering.getScene(), this, + environment); + //mSkyManager = 0; mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); @@ -412,6 +420,7 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) void RenderingManager::setSunColour(const Ogre::ColourValue& colour) { + if (!mSunEnabled) return; mSun->setDiffuseColour(colour); mSun->setSpecularColour(colour); mTerrainManager->setDiffuse(colour); @@ -425,12 +434,21 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) void RenderingManager::sunEnable() { - if (mSun) mSun->setVisible(true); + // Don't disable the light, as the shaders assume the first light to be directional. + //if (mSun) mSun->setVisible(true); + mSunEnabled = true; } void RenderingManager::sunDisable() { - if (mSun) mSun->setVisible(false); + // Don't disable the light, as the shaders assume the first light to be directional. + //if (mSun) mSun->setVisible(false); + mSunEnabled = false; + if (mSun) + { + mSun->setDiffuseColour(ColourValue(0,0,0)); + mSun->setSpecularColour(ColourValue(0,0,0)); + } } void RenderingManager::setSunDirection(const Ogre::Vector3& direction) @@ -475,4 +493,9 @@ const bool RenderingManager::useMRT() return Settings::Manager::getBool("shader", "Water"); } +Shadows* RenderingManager::getShadows() +{ + return mShadows; +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index da9c55cb5..a563d78c6 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -25,8 +25,6 @@ #include "objects.hpp" #include "actors.hpp" #include "player.hpp" -#include "water.hpp" -#include "localmap.hpp" #include "occlusionquery.hpp" namespace Ogre @@ -45,7 +43,10 @@ namespace MWWorld namespace MWRender { - + class Shadows; + class ShaderHelper; + class LocalMap; + class Water; class RenderingManager: private RenderingInterface { @@ -114,6 +115,8 @@ class RenderingManager: private RenderingInterface { bool occlusionQuerySupported() { return mOcclusionQuery->supported(); }; OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; }; + Shadows* getShadows(); + void setGlare(bool glare); void skyEnable (); void skyDisable (); @@ -149,6 +152,8 @@ class RenderingManager: private RenderingInterface { void setAmbientMode(); + bool mSunEnabled; + SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; @@ -180,6 +185,10 @@ class RenderingManager: private RenderingInterface { MWRender::Debugging *mDebugging; MWRender::LocalMap* mLocalMap; + + MWRender::Shadows* mShadows; + + MWRender::ShaderHelper* mShaderHelper; }; } diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp new file mode 100644 index 000000000..93f960dc4 --- /dev/null +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -0,0 +1,308 @@ +#include "shaderhelper.hpp" +#include "renderingmanager.hpp" +#include "shadows.hpp" + +#include +#include +#include + +#include + +using namespace Ogre; +using namespace MWRender; + +ShaderHelper::ShaderHelper(RenderingManager* rend) +{ + mRendering = rend; + applyShaders(); +} + +void ShaderHelper::applyShaders() +{ + if (!Settings::Manager::getBool("shaders", "Objects")) return; + + bool mrt = RenderingManager::useMRT(); + bool shadows = Settings::Manager::getBool("enabled", "Shadows"); + bool split = Settings::Manager::getBool("split", "Shadows"); + + // shader for normal rendering + createShader(mrt, shadows, split, "main"); + + // fallback shader without mrt and without shadows + // (useful for reflection and for minimap) + createShader(false, false, false, "main_fallback"); +} + +void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool split, const std::string& name) +{ + HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); + + const int numsplits = 3; + + // the number of lights to support. + // when rendering an object, OGRE automatically picks the lights that are + // closest to the object being rendered. unfortunately this mechanism does + // not work perfectly for objects batched together (they will all use the same + // lights). to work around this, we are simply pushing the maximum number + // of lights here in order to minimize disappearing lights. + int num_lights = Settings::Manager::getInt("num lights", "Objects"); + + { + // vertex + HighLevelGpuProgramPtr vertex; + if (!mgr.getByName(name+"_vp").isNull()) + mgr.remove(name+"_vp"); + + vertex = mgr.createProgram(name+"_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + "cg", GPT_VERTEX_PROGRAM); + vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1"); + vertex->setParameter("entry_point", "main_vp"); + StringUtil::StrStreamType outStream; + outStream << + "void main_vp( \n" + " float4 position : POSITION, \n" + " float4 normal : NORMAL, \n" + " float4 colour : COLOR, \n" + " in float2 uv : TEXCOORD0, \n" + " out float2 oUV : TEXCOORD0, \n" + " out float4 oPosition : POSITION, \n" + " out float4 oPositionObjSpace : TEXCOORD1, \n" + " out float4 oNormal : TEXCOORD2, \n" + " out float oDepth : TEXCOORD3, \n" + " out float4 oVertexColour : TEXCOORD4, \n"; + if (shadows && !split) outStream << + " out float4 oLightSpacePos0 : TEXCOORD5, \n" + " uniform float4x4 worldMatrix, \n" + " uniform float4x4 texViewProjMatrix0, \n"; + else + { + for (int i=0; isetSource(outStream.str()); + vertex->load(); + vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); + if (shadows) + { + vertex->getDefaultParameters()->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX); + if (!split) + vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix0", GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, 0); + else + { + for (int i=0; igetDefaultParameters()->setNamedAutoConstant("texViewProjMatrix"+StringConverter::toString(i), GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); + } + } + } + } + + { + // fragment + HighLevelGpuProgramPtr fragment; + if (!mgr.getByName(name+"_fp").isNull()) + mgr.remove(name+"_fp"); + + fragment = mgr.createProgram(name+"_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + "cg", GPT_FRAGMENT_PROGRAM); + fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1"); + fragment->setParameter("entry_point", "main_fp"); + StringUtil::StrStreamType outStream; + + if (shadows) outStream << + "float depthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n" + "{ \n" + " shadowMapPos /= shadowMapPos.w; \n" + " float3 o = float3(offset.xy, -offset.x) * 0.3f; \n" + " float c = (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right \n" + " return c / 4; \n" + "} \n"; + + outStream << + "void main_fp( \n" + " in float2 uv : TEXCOORD0, \n" + " out float4 oColor : COLOR, \n" + " uniform sampler2D texture : register(s0), \n" + " float4 positionObjSpace : TEXCOORD1, \n" + " float4 normal : TEXCOORD2, \n" + " float iDepth : TEXCOORD3, \n" + " float4 vertexColour : TEXCOORD4, \n" + " uniform float4 fogColour, \n" + " uniform float4 fogParams, \n"; + + if (shadows) outStream << + " uniform float4 shadowFar_fadeStart, \n"; + + if (shadows && !split) outStream << + " uniform sampler2D shadowMap : register(s1), \n" + " float4 lightSpacePos0 : TEXCOORD5, \n" + " uniform float4 invShadowmapSize0, \n"; + else + { + outStream << + " uniform float4 pssmSplitPoints, \n"; + for (int i=0; i shadowFar_fadeStart.x) ? 1 : ((iDepth > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); \n" + " lightColour.xyz += shadow * lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<setSource(outStream.str()); + fragment->load(); + + for (int i=0; igetDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i); + fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i); + fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); + } + fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); + fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); + + if (shadows) + { + fragment->getDefaultParameters()->setNamedConstant("shadowFar_fadeStart", Vector4(mRendering->getShadows()->getShadowFar(), mRendering->getShadows()->getFadeStart()*mRendering->getShadows()->getShadowFar(), 0, 0)); + for (int i=0; i < (split ? numsplits : 1); ++i) + { + fragment->getDefaultParameters()->setNamedAutoConstant("invShadowmapSize" + StringConverter::toString(i), GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i+1); + } + if (split) + { + Vector4 splitPoints; + const PSSMShadowCameraSetup::SplitPointList& splitPointList = mRendering->getShadows()->getPSSMSetup()->getSplitPoints(); + // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) + for (int i = 1; i < numsplits; ++i) + { + splitPoints[i-1] = splitPointList[i]; + } + fragment->getDefaultParameters()->setNamedConstant("pssmSplitPoints", splitPoints); + } + } + + if (mrt) + fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); + } +} diff --git a/apps/openmw/mwrender/shaderhelper.hpp b/apps/openmw/mwrender/shaderhelper.hpp new file mode 100644 index 000000000..356d345de --- /dev/null +++ b/apps/openmw/mwrender/shaderhelper.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_SHADERHELPER_H +#define GAME_SHADERHELPER_H + +#include + +namespace MWRender +{ + class RenderingManager; + + /// + /// \brief manages the main shader + /// + class ShaderHelper + { + public: + ShaderHelper(RenderingManager* rend); + + void applyShaders(); + ///< apply new settings + + private: + RenderingManager* mRendering; + + void createShader(const bool mrt, const bool shadows, const bool split, const std::string& name); + }; + +} + +#endif diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp new file mode 100644 index 000000000..9c150f0c6 --- /dev/null +++ b/apps/openmw/mwrender/shadows.cpp @@ -0,0 +1,175 @@ +#include "shadows.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "renderconst.hpp" + +using namespace Ogre; +using namespace MWRender; + +Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : + mShadowFar(1000), mFadeStart(0.9) +{ + mRendering = rend; + mSceneMgr = mRendering->getScene(); + recreate(); +} + +void Shadows::recreate() +{ + bool enabled = Settings::Manager::getBool("enabled", "Shadows"); + + // Split shadow maps are currently disabled because the terrain cannot cope with them + // (Too many texture units) Solution would be a multi-pass terrain material + bool split = Settings::Manager::getBool("split", "Shadows"); + //const bool split = false; + + if (!enabled) + { + mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); + return; + } + + int texsize = Settings::Manager::getInt("texture size", "Shadows"); + mSceneMgr->setShadowTextureSize(texsize); + + mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED); + + // no point light shadows, i'm afraid. might revisit this with Deferred Shading + mSceneMgr->setShadowTextureCountPerLightType(Light::LT_POINT, 0); + + mSceneMgr->setShadowTextureCountPerLightType(Light::LT_DIRECTIONAL, split ? 3 : 1); + mSceneMgr->setShadowTextureCount(split ? 3 : 1); + + mSceneMgr->setShadowTextureSelfShadow(true); + mSceneMgr->setShadowCasterRenderBackFaces(true); + mSceneMgr->setShadowTextureCasterMaterial("depth_shadow_caster"); + mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); + mSceneMgr->setShadowDirLightTextureOffset(0.9); + mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); + mSceneMgr->setShowDebugShadows(true); + + mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows"); + mSceneMgr->setShadowFarDistance(mShadowFar); + + mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); + + ShadowCameraSetupPtr shadowCameraSetup; + if (split) + { + mPSSMSetup = new PSSMShadowCameraSetup(); + mPSSMSetup->setSplitPadding(5); + mPSSMSetup->calculateSplitPoints(3, mRendering->getCamera()->getNearClipDistance(), mShadowFar); + + const Real adjustFactors[3] = {64, 64, 64}; + for (int i=0; i < 3; ++i) + { + mPSSMSetup->setOptimalAdjustFactor(i, adjustFactors[i]); + /*if (i==0) + mSceneMgr->setShadowTextureConfig(i, texsize, texsize, Ogre::PF_FLOAT32_R); + else if (i ==1) + mSceneMgr->setShadowTextureConfig(i, texsize/2, texsize/2, Ogre::PF_FLOAT32_R); + else if (i ==2) + mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/ + } + + shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup); + } + else + { + LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup(); + lispsmSetup->setOptimalAdjustFactor(2); + //lispsmSetup->setCameraLightDirectionThreshold(Degree(0)); + //lispsmSetup->setUseAggressiveFocusRegion(false); + shadowCameraSetup = ShadowCameraSetupPtr(lispsmSetup); + } + mSceneMgr->setShadowCameraSetup(shadowCameraSetup); + + // Set visibility mask for the shadow render textures + int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows") + + (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows") + + RV_Misc * Settings::Manager::getBool("misc shadows", "Shadows"); + + for (int i = 0; i < (split ? 3 : 1); ++i) + { + TexturePtr shadowTexture = mSceneMgr->getShadowTexture(i); + Viewport* vp = shadowTexture->getBuffer()->getRenderTarget()->getViewport(0); + vp->setVisibilityMask(visibilityMask); + } + + // -------------------------------------------------------------------------------------------------------------------- + // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- + // -------------------------------------------------------------------------------------------------------------------- + /* + OverlayManager& mgr = OverlayManager::getSingleton(); + Overlay* overlay; + + // destroy if already exists + if (overlay = mgr.getByName("DebugOverlay")) + mgr.destroy(overlay); + + overlay = mgr.create("DebugOverlay"); + for (size_t i = 0; i < (split ? 3 : 1); ++i) { + TexturePtr tex = mRendering->getScene()->getShadowTexture(i); + + // Set up a debug panel to display the shadow + + if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i))) + MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i)); + MaterialPtr debugMat = MaterialManager::getSingleton().create( + "Ogre/DebugTexture" + StringConverter::toString(i), + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); + TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); + t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); + + OverlayContainer* debugPanel; + + // destroy container if exists + try + { + if (debugPanel = + static_cast( + mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i) + ))) + mgr.destroyOverlayElement(debugPanel); + } + catch (Ogre::Exception&) {} + + debugPanel = (OverlayContainer*) + (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i))); + debugPanel->_setPosition(0.8, i*0.25); + debugPanel->_setDimensions(0.2, 0.24); + debugPanel->setMaterialName(debugMat->getName()); + debugPanel->show(); + overlay->add2D(debugPanel); + overlay->show(); + } + */ +} + +PSSMShadowCameraSetup* Shadows::getPSSMSetup() +{ + return mPSSMSetup; +} + +float Shadows::getShadowFar() const +{ + return mShadowFar; +} + +float Shadows::getFadeStart() const +{ + return mFadeStart; +} diff --git a/apps/openmw/mwrender/shadows.hpp b/apps/openmw/mwrender/shadows.hpp new file mode 100644 index 000000000..bc2b141f7 --- /dev/null +++ b/apps/openmw/mwrender/shadows.hpp @@ -0,0 +1,39 @@ +#ifndef GAME_SHADOWS_H +#define GAME_SHADOWS_H + +// forward declares +namespace Ogre +{ + class SceneManager; + class PSSMShadowCameraSetup; +} +namespace OEngine{ + namespace Render{ + class OgreRenderer; + } +} + +namespace MWRender +{ + class Shadows + { + public: + Shadows(OEngine::Render::OgreRenderer* rend); + + void recreate(); + + Ogre::PSSMShadowCameraSetup* getPSSMSetup(); + float getShadowFar() const; + float getFadeStart() const; + + protected: + OEngine::Render::OgreRenderer* mRendering; + Ogre::SceneManager* mSceneMgr; + + Ogre::PSSMShadowCameraSetup* mPSSMSetup; + float mShadowFar; + float mFadeStart; + }; +} + +#endif diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 188ec3b83..859da2dc1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -102,6 +102,7 @@ void BillboardObject::init(const String& textureName, mNode->setPosition(finalPosition); mNode->attachObject(mBBSet); mBBSet->createBillboard(0,0,0); + mBBSet->setCastShadows(false); mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mMaterial->removeAllTechniques(); @@ -450,6 +451,7 @@ void SkyManager::create() Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); + night1_ent->setCastShadows(false); mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight->attachObject(night1_ent); @@ -525,6 +527,7 @@ void SkyManager::create() // Atmosphere (day) mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif"); + atmosphere_ent->setCastShadows(false); ModVertexAlpha(atmosphere_ent, 0); @@ -596,6 +599,7 @@ void SkyManager::create() SceneNode* clouds_node = mRootNode->createChildSceneNode(); clouds_node->attachObject(clouds_ent); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); + clouds_ent->setCastShadows(false); // Clouds vertex shader HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -677,6 +681,8 @@ void SkyManager::create() mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); + mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds"); mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); mCreated = true; @@ -766,12 +772,14 @@ void SkyManager::disable() void SkyManager::setMoonColour (bool red) { + if (!mCreated) return; mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1.0, 1.0, 1.0)); } void SkyManager::setCloudsOpacity(float opacity) { + if (!mCreated) return; mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity)); } @@ -927,11 +935,13 @@ void SkyManager::setThunder(const float factor) void SkyManager::setMasserFade(const float fade) { + if (!mCreated) return; mMasser->setVisibility(fade); } void SkyManager::setSecundaFade(const float fade) { + if (!mCreated) return; mSecunda->setVisibility(fade); } diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 67dd4e0b0..f9b43655b 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -7,7 +7,8 @@ #include "terrainmaterial.hpp" #include "terrain.hpp" #include "renderconst.hpp" - +#include "shadows.hpp" +#include using namespace Ogre; @@ -16,8 +17,8 @@ namespace MWRender //---------------------------------------------------------------------------------------------- - TerrainManager::TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& evn) : - mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)) + TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& evn) : + mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) { TerrainMaterialGeneratorPtr matGen; @@ -48,9 +49,19 @@ namespace MWRender mActiveProfile->setLayerSpecularMappingEnabled(false); mActiveProfile->setLayerNormalMappingEnabled(false); mActiveProfile->setLayerParallaxMappingEnabled(false); - mActiveProfile->setReceiveDynamicShadowsEnabled(false); - //composite maps lead to a drastic reduction in loading time so are + bool shadows = Settings::Manager::getBool("enabled", "Shadows"); + mActiveProfile->setReceiveDynamicShadowsEnabled(shadows); + mActiveProfile->setReceiveDynamicShadowsDepth(shadows); + if (Settings::Manager::getBool("split", "Shadows")) + mActiveProfile->setReceiveDynamicShadowsPSSM(mRendering->getShadows()->getPSSMSetup()); + else + mActiveProfile->setReceiveDynamicShadowsPSSM(0); + + mActiveProfile->setShadowFar(mRendering->getShadows()->getShadowFar()); + mActiveProfile->setShadowFadeStart(mRendering->getShadows()->getFadeStart()); + + //composite maps lead to a drastic increase in loading time so are //disabled mActiveProfile->setCompositeMapEnabled(false); diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 29a4ba36b..dc4a2388c 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -24,7 +24,7 @@ namespace MWRender{ */ class TerrainManager{ public: - TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& env); + TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& env); virtual ~TerrainManager(); void setDiffuse(const Ogre::ColourValue& diffuse); @@ -37,6 +37,7 @@ namespace MWRender{ Ogre::TerrainGroup mTerrainGroup; const MWWorld::Environment& mEnvironment; + RenderingManager* mRendering; Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 87798006c..57bea5388 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -86,6 +86,7 @@ namespace Ogre , mPSSM(0) , mDepthShadows(false) , mLowLodShadows(false) + , mShadowFar(1300) { } @@ -102,6 +103,24 @@ namespace Ogre terrain->_setLightMapRequired(mLightmapEnabled, true); terrain->_setCompositeMapRequired(mCompositeMapEnabled); } + //--------------------------------------------------------------------- + void TerrainMaterialGeneratorB::SM2Profile::setShadowFar(float far) + { + if (mShadowFar != far) + { + mShadowFar = far; + mParent->_markChanged(); + } + } + //--------------------------------------------------------------------- + void TerrainMaterialGeneratorB::SM2Profile::setShadowFadeStart(float fadestart) + { + if (mShadowFadeStart != fadestart) + { + mShadowFadeStart = fadestart; + mParent->_markChanged(); + } + } //--------------------------------------------------------------------- void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled) { @@ -462,6 +481,7 @@ namespace Ogre StringUtil::StrStreamType sourceStr; generateFragmentProgramSource(prof, terrain, tt, sourceStr); + ret->setSource(sourceStr.str()); ret->load(); defaultFpParams(prof, terrain, tt, ret); @@ -533,8 +553,8 @@ namespace Ogre GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); if (prof->getReceiveDynamicShadowsDepth()) { - params->setNamedAutoConstant("depthRange" + StringConverter::toString(i), - GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i); + //params->setNamedAutoConstant("depthRange" + StringConverter::toString(i), + //GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i); } } } @@ -567,6 +587,7 @@ namespace Ogre if (prof->isShadowingEnabled(tt, terrain)) { + params->setNamedConstant("shadowFar_fadeStart", Vector4(prof->mShadowFar, prof->mShadowFadeStart * prof->mShadowFar, 0, 0)); uint numTextures = 1; if (prof->getReceiveDynamicShadowsPSSM()) { @@ -732,7 +753,7 @@ namespace Ogre ret->unload(); } - ret->setParameter("profiles", "vs_3_0 vs_2_0 arbvp1"); + ret->setParameter("profiles", "vs_3_0 vs_2_0 vp40 arbvp1"); ret->setParameter("entry_point", "main_vp"); return ret; @@ -790,9 +811,9 @@ namespace Ogre outStream << "out float4 oPos : POSITION,\n" - "out float4 oPosObj : TEXCOORD0 \n"; + "out float4 oPosObj : COLOR \n"; - uint texCoordSet = 1; + uint texCoordSet = 0; outStream << ", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n"; @@ -818,8 +839,8 @@ namespace Ogre if (fog) { outStream << - ", uniform float4 fogParams\n" - ", out float fogVal : COLOR\n"; + ", uniform float4 fogParams\n"; + //", out float fogVal : COLOR\n"; } if (prof->isShadowingEnabled(tt, terrain)) @@ -831,7 +852,7 @@ namespace Ogre if (texCoordSet > 8) { OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, - "Requested options require too many texture coordinate sets! Try reducing the number of layers.", + "Requested options require too many texture coordinate sets! Try reducing the number of layers. requested: " + StringConverter::toString(texCoordSet), __FUNCTION__); } @@ -917,9 +938,9 @@ namespace Ogre outStream << "void main_fp(\n" - "float4 position : TEXCOORD0,\n"; + "float4 position : COLOR,\n"; - uint texCoordSet = 1; + uint texCoordSet = 0; outStream << "float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n"; @@ -948,8 +969,8 @@ namespace Ogre if (fog) { outStream << - "uniform float3 fogColour, \n" - "float fogVal : COLOR,\n"; + "uniform float3 fogColour, \n"; + //"float fogVal : COLOR,\n"; } uint currentSamplerIdx = 0; @@ -1046,6 +1067,7 @@ namespace Ogre " float4 outputCol;\n" " float shadow = 1.0;\n" " float2 uv = uvMisc.xy;\n" + " float fogVal = position.w; \n" // base colour " outputCol = float4(0,0,0,1);\n"; @@ -1257,13 +1279,15 @@ namespace Ogre if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) { outStream << - " fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n"; + " float fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n"; } else { outStream << - " fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n"; + " float fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n"; } + outStream << + " oPosObj.w = fogVal; \n"; } if (prof->isShadowingEnabled(tt, terrain)) @@ -1364,7 +1388,7 @@ namespace Ogre outStream << "// Simple PCF \n" "// Number of samples in one dimension (square for total samples) \n" - "#define NUM_SHADOW_SAMPLES_1D 2.0 \n" + "#define NUM_SHADOW_SAMPLES_1D 1.0 \n" "#define SHADOW_FILTER_SCALE 1 \n" "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n" @@ -1377,28 +1401,18 @@ namespace Ogre if (prof->getReceiveDynamicShadowsDepth()) { outStream << - "float calcDepthShadow(sampler2D shadowMap, float4 uv, float invShadowMapSize) \n" - "{ \n" - " // 4-sample PCF \n" - - " float shadow = 0.0; \n" - " float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n" - " for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n" - " for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n" - " { \n" - " float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n" - " // manually project and assign derivatives \n" - " // to avoid gradient issues inside loops \n" - " newUV = newUV / newUV.w; \n" - " float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n" - " if (depth >= 1 || depth >= uv.z)\n" - " shadow += 1.0;\n" - " } \n" - - " shadow /= SHADOW_SAMPLES; \n" - - " return shadow; \n" - "} \n"; + "float calcDepthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n" + " { \n" + " shadowMapPos = shadowMapPos / shadowMapPos.w; \n" + " float2 uv = shadowMapPos.xy; \n" + " float3 o = float3(offset, -offset.x) * 0.3f; \n" + " // Note: We using 2x2 PCF. Good enough and is alot faster. \n" + " float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n" + " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n" + " return c / 4; \n" + " } \n"; } else { @@ -1436,7 +1450,7 @@ namespace Ogre { outStream << "\n "; for (uint i = 0; i < numTextures; ++i) - outStream << "float invShadowmapSize" << i << ", "; + outStream << "float2 invShadowmapSize" << i << ", "; } outStream << "\n" " float4 pssmSplitPoints, float camDepth) \n" @@ -1458,7 +1472,7 @@ namespace Ogre if (prof->getReceiveDynamicShadowsDepth()) { outStream << - " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n"; + " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << ".xy); \n"; } else { @@ -1520,8 +1534,8 @@ namespace Ogre if (prof->getReceiveDynamicShadowsDepth()) { // make linear - outStream << - "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; + //outStream << + // "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; } } @@ -1538,6 +1552,8 @@ namespace Ogre // in semantics & params uint numTextures = 1; + outStream << + ", uniform float4 shadowFar_fadeStart \n"; if (prof->getReceiveDynamicShadowsPSSM()) { numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); @@ -1554,7 +1570,7 @@ namespace Ogre if (prof->getReceiveDynamicShadowsDepth()) { outStream << - ", uniform float inverseShadowmapSize" << i << " \n"; + ", uniform float4 inverseShadowmapSize" << i << " \n"; } } @@ -1589,7 +1605,7 @@ namespace Ogre { outStream << "\n "; for (uint i = 0; i < numTextures; ++i) - outStream << "inverseShadowmapSize" << i << ", "; + outStream << "inverseShadowmapSize" << i << ".xy, "; } outStream << "\n" << " pssmSplitPoints, camDepth);\n"; @@ -1600,7 +1616,7 @@ namespace Ogre if (prof->getReceiveDynamicShadowsDepth()) { outStream << - " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);"; + " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0.xy);"; } else { @@ -1609,7 +1625,11 @@ namespace Ogre } } - outStream << + outStream << + " float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n" + " float fade = 1-((uvMisc.z - shadowFar_fadeStart.y) / fadeRange); \n" + " rtshadow = (uvMisc.z > shadowFar_fadeStart.x) ? 1 : ((uvMisc.z > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n" + " rtshadow = (1-(1-rtshadow)*0.6); \n" // make the shadow a little less intensive " shadow = min(shadow, rtshadow);\n"; } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index 3cb316347..db916bf25 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -73,6 +73,9 @@ namespace Ogre void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain); void requestOptions(Terrain* terrain); + void setShadowFar(float far); + void setShadowFadeStart(float fadestart); + /** Whether to support normal mapping per layer in the shader (default true). */ bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; } @@ -245,6 +248,8 @@ namespace Ogre bool mDepthShadows; bool mLowLodShadows; bool mSM3Available; + float mShadowFar; + float mShadowFadeStart; bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7981def0b..85fb2ee99 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -31,6 +31,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); mWater->setRenderQueueGroup(RQG_Water); + mWater->setCastShadows(false); mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") + RV_Statics * Settings::Manager::getBool("reflect statics", "Water") @@ -42,6 +43,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); mWaterNode->setPosition(0, mTop, 0); + mReflectionCamera = mSceneManager->createCamera("ReflectionCamera"); + if(!(cell->data.flags & cell->Interior)) { mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); @@ -51,17 +54,20 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); + TexturePtr tex; if (Settings::Manager::getBool("shader", "Water")) { - TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); + tex = TextureManager::getSingleton().createManual("WaterReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET); RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); - Viewport* vp = rtt->addViewport(mCamera); + Viewport* vp = rtt->addViewport(mReflectionCamera); vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); vp->setVisibilityMask( mVisibilityFlags ); + // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) + //vp->setMaterialScheme("Fallback"); rtt->addListener(this); rtt->setActive(true); @@ -74,6 +80,55 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mWater->setMaterial(mMaterial); mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); + + + // ---------------------------------------------------------------------------------------------- + // ---------------------------------- reflection debug overlay ---------------------------------- + // ---------------------------------------------------------------------------------------------- + /* + if (Settings::Manager::getBool("shader", "Water")) + { + OverlayManager& mgr = OverlayManager::getSingleton(); + Overlay* overlay; + // destroy if already exists + if (overlay = mgr.getByName("ReflectionDebugOverlay")) + mgr.destroy(overlay); + + overlay = mgr.create("ReflectionDebugOverlay"); + + if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) + MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); + MaterialPtr debugMat = MaterialManager::getSingleton().create( + "Ogre/ReflectionDebugTexture", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); + TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); + t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); + + OverlayContainer* debugPanel; + + // destroy container if exists + try + { + if (debugPanel = + static_cast( + mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" + ))) + mgr.destroyOverlayElement(debugPanel); + } + catch (Ogre::Exception&) {} + + debugPanel = (OverlayContainer*) + (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel")); + debugPanel->_setPosition(0, 0.55); + debugPanel->_setDimensions(0.3, 0.3); + debugPanel->setMaterialName(debugMat->getName()); + debugPanel->show(); + overlay->add2D(debugPanel); + overlay->show(); + } + */ } void Water::setActive(bool active) @@ -162,6 +217,12 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { + mReflectionCamera->setOrientation(mCamera->getDerivedOrientation()); + mReflectionCamera->setPosition(mCamera->getDerivedPosition()); + mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); + mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); + mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); + mReflectionCamera->setFOVy(mCamera->getFOVy()); if (evt.source == mReflectionTarget) { mWater->setVisible(false); @@ -174,8 +235,8 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mSky->setSkyPosition(pos); mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); - mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); - mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); + mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); + mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); } } @@ -187,8 +248,8 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mSky->resetSkyPosition(); mSky->scaleSky(1); - mCamera->disableReflection(); - mCamera->disableCustomNearClipPlane(); + mReflectionCamera->disableCustomNearClipPlane(); + mReflectionCamera->disableReflection(); } } diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 0e23f5b0c..3fb1b07b7 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -39,6 +39,8 @@ namespace MWRender { void createMaterial(); Ogre::MaterialPtr mMaterial; + Ogre::Camera* mReflectionCamera; + Ogre::RenderTarget* mReflectionTarget; bool mUnderwaterEffect; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 835534eff..02e4e5447 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -291,6 +291,42 @@ void NIFLoader::createMaterial(const String &name, else warn("Unhandled alpha setting for texture " + texName); } + else + { + material->getTechnique(0)->setShadowCasterMaterial("depth_shadow_caster_noalpha"); + } + } + + if (Settings::Manager::getBool("enabled", "Shadows")) + { + bool split = Settings::Manager::getBool("split", "Shadows"); + const int numsplits = 3; + for (int i = 0; i < (split ? numsplits : 1); ++i) + { + TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState(); + tu->setName("shadowMap" + StringConverter::toString(i)); + tu->setContentType(TextureUnitState::CONTENT_SHADOW); + tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER); + tu->setTextureBorderColour(ColourValue::White); + } + } + + if (Settings::Manager::getBool("shaders", "Objects")) + { + material->getTechnique(0)->getPass(0)->setVertexProgram("main_vp"); + material->getTechnique(0)->getPass(0)->setFragmentProgram("main_fp"); + } + + // Create a fallback technique without shadows and without mrt + Technique* tech2 = material->createTechnique(); + tech2->setSchemeName("Fallback"); + Pass* pass2 = tech2->createPass(); + pass2->createTextureUnitState(texName); + pass2->setVertexColourTracking(TVC_DIFFUSE); + if (Settings::Manager::getBool("shaders", "Objects")) + { + pass2->setVertexProgram("main_fallback_vp"); + pass2->setFragmentProgram("main_fallback_fp"); } // Add material bells and whistles @@ -299,151 +335,6 @@ void NIFLoader::createMaterial(const String &name, material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha); material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); material->setShininess(glossiness); - - if (Settings::Manager::getBool("shaders", "Objects")) - { - bool mrt = Settings::Manager::getBool("shader", "Water"); - - // Create shader for the material - // vertex - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - - HighLevelGpuProgramPtr vertex; - if (mgr.getByName("main_vp").isNull()) - { - vertex = mgr.createProgram("main_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1"); - vertex->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream; - outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " float4 normal : NORMAL, \n" - " float4 colour : COLOR, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " out float4 oPositionObjSpace : TEXCOORD1, \n" - " out float4 oNormal : TEXCOORD2, \n" - " out float oDepth : TEXCOORD3, \n" - " out float4 oVertexColour : TEXCOORD4, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oVertexColour = colour; \n" - " oUV = uv; \n" - " oNormal = normal; \n" - " oPosition = mul( worldViewProj, position ); \n" - " oDepth = oPosition.z; \n" - " oPositionObjSpace = position; \n" - "}"; - vertex->setSource(outStream.str()); - vertex->load(); - vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - } - else - vertex = mgr.getByName("main_vp"); - material->getTechnique(0)->getPass(0)->setVertexProgram(vertex->getName()); - - // the number of lights to support. - // when rendering an object, OGRE automatically picks the lights that are - // closest to the object being rendered. unfortunately this mechanism does - // not work perfectly for objects batched together (they will all use the same - // lights). to work around this, we are simply pushing the maximum number - // of lights here in order to minimize disappearing lights. - int num_lights = Settings::Manager::getInt("num lights", "Objects"); - - // fragment - HighLevelGpuProgramPtr fragment; - if (mgr.getByName("main_fp").isNull()) - { - fragment = mgr.createProgram("main_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1"); - fragment->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream; - outStream << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" - " uniform sampler2D texture : TEXUNIT0, \n" - " float4 positionObjSpace : TEXCOORD1, \n" - " float4 normal : TEXCOORD2, \n" - " float iDepth : TEXCOORD3, \n" - " float4 vertexColour : TEXCOORD4, \n" - " uniform float4 fogColour, \n" - " uniform float4 fogParams, \n"; - - if (mrt) outStream << - " out float4 oColor1 : COLOR1, \n" - " uniform float far, \n"; - - for (int i=0; isetSource(outStream.str()); - fragment->load(); - - for (int i=0; igetDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i); - fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i); - fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); - } - fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); - if (mrt) - fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); - } - else - fragment = mgr.getByName("main_fp"); - material->getTechnique(0)->getPass(0)->setFragmentProgram(fragment->getName()); - } } // Takes a name and adds a unique part to it. This is just used to diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 507f82c1a..8ab3d5b51 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -11,3 +11,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.material "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.material" COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.cg "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.cg" COPYONLY) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d5a8bdfd4..4d2d46fca 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -18,6 +18,32 @@ anisotropy = 4 # Number of texture mipmaps to generate num mipmaps = 5 +[Shadows] +# Shadows are only supported when object shaders are on! +enabled = false + +# Split the shadow maps, allows for a larger shadow distance +# Warning: enabling this will cause some terrain textures to disappear due to +# hitting the texture unit limit of the terrain material +split = false + +# Increasing shadow distance will lower the shadow quality. +# Uses "shadow distance" or "split shadow distance" depending on "split" setting. +shadow distance = 1300 +# This one shouldn't be too low, otherwise you'll see artifacts. Use at least 2x max viewing distance. +split shadow distance = 14000 + +# Size of the shadow textures, higher means higher quality +texture size = 1024 + +# Turn on/off various shadow casters +actor shadows = true +misc shadows = true +statics shadows = true + +# Fraction of the total shadow distance after which the shadow starts to fade out +fade start = 0.8 + [HUD] # FPS counter # 0: not visible @@ -64,15 +90,10 @@ num lights = 8 shader = true rtt size = 512 - reflect terrain = true - reflect statics = false - reflect small statics = false - reflect actors = true - reflect misc = false # Enable underwater effect. It is not resource intensive, so only disable it if you have problems. diff --git a/files/shadows/depthshadowcaster.cg b/files/shadows/depthshadowcaster.cg new file mode 100644 index 000000000..3457a4f8d --- /dev/null +++ b/files/shadows/depthshadowcaster.cg @@ -0,0 +1,51 @@ +void main_vp( + float4 position : POSITION, + float2 uv : TEXCOORD0, + + out float4 oPosition : POSITION, + out float2 oDepth : TEXCOORD0, + out float2 oUv : TEXCOORD1, + + uniform float4x4 wvpMat) +{ + // this is the view space position + oPosition = mul(wvpMat, position); + + // depth info for the fragment. + oDepth.x = oPosition.z; + oDepth.y = oPosition.w; + + // clamp z to zero. seem to do the trick. :-/ + oPosition.z = max(oPosition.z, 0); + + oUv = uv; +} + +void main_fp( + float2 depth : TEXCOORD0, + float2 uv : TEXCOORD1, + uniform sampler2D texture1 : register(s0), + + out float4 oColour : COLOR) +{ + float finalDepth = depth.x / depth.y; + + // use alpha channel of the first texture + float alpha = tex2D(texture1, uv).a; + + // discard if alpha is less than 0.5 + clip((alpha >= 0.5) ? 1 : -1); + + oColour = float4(finalDepth, finalDepth, finalDepth, 1); +} + +void main_fp_noalpha( + float2 depth : TEXCOORD0, + float2 uv : TEXCOORD1, + + out float4 oColour : COLOR) +{ + float finalDepth = depth.x / depth.y; + + oColour = float4(finalDepth, finalDepth, finalDepth, 1); +} diff --git a/files/shadows/depthshadowcaster.material b/files/shadows/depthshadowcaster.material new file mode 100644 index 000000000..9ff51c5b1 --- /dev/null +++ b/files/shadows/depthshadowcaster.material @@ -0,0 +1,67 @@ +vertex_program depth_shadow_caster_vs cg +{ + source depthshadowcaster.cg + profiles vs_1_1 arbvp1 + entry_point main_vp + + default_params + { + param_named_auto wvpMat worldviewproj_matrix + } +} + +fragment_program depth_shadow_caster_ps cg +{ + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp + + default_params + { + } +} + +fragment_program depth_shadow_caster_ps_noalpha cg +{ + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp_noalpha + + default_params + { + } +} + +material depth_shadow_caster +{ + technique + { + pass + { + vertex_program_ref depth_shadow_caster_vs + { + } + + fragment_program_ref depth_shadow_caster_ps + { + } + } + } +} + +material depth_shadow_caster_noalpha +{ + technique + { + pass + { + vertex_program_ref depth_shadow_caster_vs + { + } + + fragment_program_ref depth_shadow_caster_ps_noalpha + { + } + } + } +} diff --git a/files/water/water.material b/files/water/water.material index 7ce6e7ba2..8b4ff96f5 100644 --- a/files/water/water.material +++ b/files/water/water.material @@ -92,7 +92,7 @@ material Water } technique { - scheme Map + scheme Fallback pass { cull_hardware none From 750d79eaf032ca8bd21f33899853e5a3595e311c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Apr 2012 18:29:36 +0200 Subject: [PATCH 113/185] added spell container class --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/spells.cpp | 77 ++++++++++++++++++++++++++++++ apps/openmw/mwmechanics/spells.hpp | 55 +++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/spells.cpp create mode 100644 apps/openmw/mwmechanics/spells.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c31a9d8fd..79f0948f9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -55,7 +55,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanager stat creaturestats magiceffects movement + mechanicsmanager stat creaturestats magiceffects movement spells ) # Main executable diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp new file mode 100644 index 000000000..2b28f0c2f --- /dev/null +++ b/apps/openmw/mwmechanics/spells.cpp @@ -0,0 +1,77 @@ + +#include "spells.hpp" + +#include + +#include "../mwworld/environment.hpp" +#include "../mwworld/world.hpp" + +#include "magiceffects.hpp" + +namespace MWMechanics +{ + void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const + { + for (std::vector::const_iterator iter = spell->effects.list.begin(); + iter!=spell->effects.list.end(); ++iter) + { + EffectParam param; + param.mMagnitude = iter->magnMax; /// \todo calculate magnitude + effects.add (EffectKey (*iter), param); + } + } + + Spells::TIterator Spells::begin (ESM::Spell::SpellType type) const + { + assert (type>=0 && type=0 && typegetStore().spells.find (spellId); + + int type = spell->data.type; + + assert (type>=0 && typegetStore().spells.find (spellId); + + int type = spell->data.type; + + TContainer::iterator iter = std::find (mSpells[type].begin(), mSpells[type].end(), spell); + + if (iter!=mSpells[type].end()) + mSpells[type].erase (iter); + } + + MagicEffects Spells::getMagicEffects (MWWorld::Environment& environment) const + { + MagicEffects effects; + + for (int i=ESM::Spell::ST_Ability; i<=ESM::Spell::ST_Curse; ++i) + for (TIterator iter (begin (static_cast (i))); + iter!=end(static_cast (i)); ++iter) + addSpell (*iter, effects); + + return effects; + } + + void Spells::clear() + { + for (int i=0; i + +#include + +namespace MWWorld +{ + struct Environment; +} + +namespace MWMechanics +{ + class MagicEffects; + + /// \brief Spell list + /// + /// This class manages known spells as well as abilities, powers and permanent negative effects like + /// diseaes. + class Spells + { + public: + + typedef std::vector TContainer; + typedef TContainer::const_iterator TIterator; + + private: + + static const int sTypes = 6; + + std::vector mSpells[sTypes]; + + void addSpell (const ESM::Spell *, MagicEffects& effects) const; + + public: + + TIterator begin (ESM::Spell::SpellType type) const; + + TIterator end (ESM::Spell::SpellType type) const; + + void add (const std::string& spell, MWWorld::Environment& environment); + /// \note Adding a spell that is already listed in *this is a no-op. + + void remove (const std::string& spell, MWWorld::Environment& environment); + + MagicEffects getMagicEffects (MWWorld::Environment& environment) const; + ///< Return sum of magic effects resulting from abilities, blights, deseases and curses. + + void clear(); + ///< Remove all spells of al types. + }; +} + +#endif From e04ccfced0867c27f8ab049096abad91f9a65b09 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Apr 2012 19:03:36 +0200 Subject: [PATCH 114/185] replaced old abilities container in CreatureStats with a Spells object --- apps/openmw/mwmechanics/creaturestats.hpp | 3 +- apps/openmw/mwmechanics/mechanicsmanager.cpp | 55 ++------------------ apps/openmw/mwmechanics/mechanicsmanager.hpp | 2 - 3 files changed, 7 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index d2edc031d..ab008da9e 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -6,6 +6,7 @@ #include "stat.hpp" #include "magiceffects.hpp" +#include "spells.hpp" namespace MWMechanics { @@ -14,7 +15,7 @@ namespace MWMechanics Stat mAttributes[8]; DynamicStat mDynamic[3]; // health, magicka, fatigue int mLevel; - std::set mAbilities; + Spells mSpells; MagicEffects mMagicEffects; }; } diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 7ed81f785..00453eee5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -23,7 +23,7 @@ namespace MWMechanics // reset creatureStats.mLevel = player->npdt52.level; - creatureStats.mAbilities.clear(); + creatureStats.mSpells.clear(); creatureStats.mMagicEffects = MagicEffects(); for (int i=0; i<27; ++i) @@ -71,7 +71,7 @@ namespace MWMechanics for (std::vector::const_iterator iter (race->powers.list.begin()); iter!=race->powers.list.end(); ++iter) { - insertSpell (*iter, ptr); + creatureStats.mSpells.add (*iter, mEnvironment); } } @@ -85,7 +85,7 @@ namespace MWMechanics for (std::vector::const_iterator iter (sign->powers.list.begin()); iter!=sign->powers.list.end(); ++iter) { - insertSpell (*iter, ptr); + creatureStats.mSpells.add (*iter, mEnvironment); } } @@ -159,59 +159,14 @@ namespace MWMechanics creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); } - void MechanicsManager::insertSpell (const std::string& id, MWWorld::Ptr& creature) - { - MWMechanics::CreatureStats& creatureStats = - MWWorld::Class::get (creature).getCreatureStats (creature); - - const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (id); - - switch (spell->data.type) - { - case ESM::Spell::ST_Ability: - - if (creatureStats.mAbilities.find (id)==creatureStats.mAbilities.end()) - { - creatureStats.mAbilities.insert (id); - } - - break; - - // TODO ST_SPELL, ST_Blight, ST_Disease, ST_Curse, ST_Power - - default: - - std::cout - << "adding unsupported spell type (" << spell->data.type - << ") to creature: " << id << std::endl; - } - } - void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature) { MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (creature).getCreatureStats (creature); - MagicEffects now; - - for (std::set::const_iterator iter (creatureStats.mAbilities.begin()); - iter!=creatureStats.mAbilities.end(); ++iter) - { - const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter); - - for (std::vector::const_iterator iter = spell->effects.list.begin(); - iter!=spell->effects.list.end(); ++iter) - { - if (iter->range==0) // self - { - EffectParam param; - param.mMagnitude = iter->magnMax; // TODO calculate magnitude - now.add (EffectKey (*iter), param); - } - } - } + MagicEffects now = creatureStats.mSpells.getMagicEffects (mEnvironment); - // TODO add effects from other spell types, active spells and equipment + /// \todo add effects from active spells and equipment MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index 2e2192638..8975329dd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -37,8 +37,6 @@ namespace MWMechanics ///< build player according to stored class/race/birthsign information. Will /// default to the values of the ESM::NPC object, if no explicit information is given. - void insertSpell (const std::string& id, MWWorld::Ptr& creature); - void adjustMagicEffects (MWWorld::Ptr& creature); public: From 77065390d7de2c09a9972e3fda90c9ed73255644 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Apr 2012 19:40:42 +0200 Subject: [PATCH 115/185] simplifying Spells class --- apps/openmw/mwmechanics/mechanicsmanager.cpp | 4 +- apps/openmw/mwmechanics/spells.cpp | 53 ++++++++------------ apps/openmw/mwmechanics/spells.hpp | 24 +++++---- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index 00453eee5..414faa414 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -71,7 +71,7 @@ namespace MWMechanics for (std::vector::const_iterator iter (race->powers.list.begin()); iter!=race->powers.list.end(); ++iter) { - creatureStats.mSpells.add (*iter, mEnvironment); + creatureStats.mSpells.add (*iter); } } @@ -85,7 +85,7 @@ namespace MWMechanics for (std::vector::const_iterator iter (sign->powers.list.begin()); iter!=sign->powers.list.end(); ++iter) { - creatureStats.mSpells.add (*iter, mEnvironment); + creatureStats.mSpells.add (*iter); } } diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 2b28f0c2f..4e8c6fa5a 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,7 +1,7 @@ #include "spells.hpp" -#include +#include #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" @@ -21,57 +21,48 @@ namespace MWMechanics } } - Spells::TIterator Spells::begin (ESM::Spell::SpellType type) const + Spells::TIterator Spells::begin() const { - assert (type>=0 && type=0 && typegetStore().spells.find (spellId); - - int type = spell->data.type; - - assert (type>=0 && typegetStore().spells.find (spellId); - - int type = spell->data.type; + TContainer::iterator iter = std::find (mSpells.begin(), mSpells.end(), spellId); - TContainer::iterator iter = std::find (mSpells[type].begin(), mSpells[type].end(), spell); - - if (iter!=mSpells[type].end()) - mSpells[type].erase (iter); + if (iter!=mSpells.end()) + mSpells.erase (iter); } - MagicEffects Spells::getMagicEffects (MWWorld::Environment& environment) const + MagicEffects Spells::getMagicEffects (const MWWorld::Environment& environment) const { MagicEffects effects; - for (int i=ESM::Spell::ST_Ability; i<=ESM::Spell::ST_Curse; ++i) - for (TIterator iter (begin (static_cast (i))); - iter!=end(static_cast (i)); ++iter) - addSpell (*iter, effects); + for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) + { + const ESM::Spell *spell = environment.mWorld->getStore().spells.find (*iter); + + if (spell->data.type==ESM::Spell::ST_Ability || spell->data.type==ESM::Spell::ST_Blight || + spell->data.type==ESM::Spell::ST_Disease || spell->data.type==ESM::Spell::ST_Curse) + addSpell (spell, effects); + } return effects; } void Spells::clear() { - for (int i=0; i - #include +#include + +namespace ESM +{ + struct Spell; +} namespace MWWorld { @@ -22,29 +26,27 @@ namespace MWMechanics { public: - typedef std::vector TContainer; + typedef std::vector TContainer; typedef TContainer::const_iterator TIterator; private: - static const int sTypes = 6; - - std::vector mSpells[sTypes]; + std::vector mSpells; void addSpell (const ESM::Spell *, MagicEffects& effects) const; public: - TIterator begin (ESM::Spell::SpellType type) const; + TIterator begin() const; - TIterator end (ESM::Spell::SpellType type) const; + TIterator end() const; - void add (const std::string& spell, MWWorld::Environment& environment); + void add (const std::string& spell); /// \note Adding a spell that is already listed in *this is a no-op. - void remove (const std::string& spell, MWWorld::Environment& environment); + void remove (const std::string& spell); - MagicEffects getMagicEffects (MWWorld::Environment& environment) const; + MagicEffects getMagicEffects (const MWWorld::Environment& environment) const; ///< Return sum of magic effects resulting from abilities, blights, deseases and curses. void clear(); From 26a529111c760e639321b87a6659e0875be0fe67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 11 Apr 2012 19:45:56 +0200 Subject: [PATCH 116/185] removed old known spell list from NpcStats --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/npcstats.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2cf4cf41c..57cc3560a 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -63,7 +63,7 @@ namespace MWClass for (std::vector::const_iterator iter (ref->base->spells.list.begin()); iter!=ref->base->spells.list.end(); ++iter) - data->mNpcStats.mKnownSpells.insert (*iter); + data->mCreatureStats.mSpells.add (*iter); // creature stats data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 59bfa2ac0..ece85f893 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -11,6 +11,8 @@ namespace MWMechanics /// \brief Additional stats for NPCs /// /// For non-NPC-specific stats, see the CreatureStats struct. + /// + /// \note For technical reasons the spell list is also handled by CreatureStats. struct NpcStats { @@ -26,7 +28,6 @@ namespace MWMechanics bool mSneak; bool mCombat; - std::set mKnownSpells; std::string mSelectedSpell; // can be an empty string (no spell selected) NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), From a727bcd4a405c1d9007b00d609114cb39b7c98cd Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 11 Apr 2012 20:13:15 +0200 Subject: [PATCH 117/185] override nif transparency settings (part 1) --- CMakeLists.txt | 4 ++ apps/openmw/engine.cpp | 8 +++ components/CMakeLists.txt | 4 ++ components/nifogre/ogre_nif_loader.cpp | 19 ++++-- components/nifoverrides/nifoverrides.cpp | 37 ++++++++++ components/nifoverrides/nifoverrides.hpp | 23 +++++++ files/transparency-overrides.cfg | 86 ++++++++++++++++++++++++ 7 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 components/nifoverrides/nifoverrides.cpp create mode 100644 components/nifoverrides/nifoverrides.hpp create mode 100644 files/transparency-overrides.cfg diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b87e3544..21de30bac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,6 +227,9 @@ endif (APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}/settings-default.cfg") +configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg + "${OpenMW_BINARY_DIR}/transparency-overrides.cfg") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local "${OpenMW_BINARY_DIR}/openmw.cfg") configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg @@ -308,6 +311,7 @@ if(DPKG_PROGRAM) #Install global configuration files INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1adcf8dca..d5ff165f8 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -349,6 +350,13 @@ void OMW::Engine::go() mFpsLevel = settings.getInt("fps", "HUD"); + // load nif overrides + NifOverrides::Overrides nifOverrides; + if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg")) + nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"); + else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) + nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); + mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()), mCfgMgr.getOgreConfigPath().string(), mCfgMgr.getLogPath().string(), diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b48c50640..8a1875d0f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -6,6 +6,10 @@ add_component_dir (settings settings ) +add_component_dir (nifoverrides + nifoverrides + ) + add_component_dir (bsa bsa_archive bsa_file ) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 02e4e5447..6f5142796 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -26,6 +26,7 @@ #include "ogre_nif_loader.hpp" #include +#include typedef unsigned char ubyte; @@ -282,11 +283,21 @@ void NIFLoader::createMaterial(const String &name, // other values. 237 basically means normal transparencly. if (alphaFlags == 237) { - // Enable transparency - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + if (result.first) + { + pass->setAlphaRejectFunction(CMPF_GREATER_EQUAL); + pass->setAlphaRejectValue(result.second); + } + else + { + // Enable transparency + pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - //pass->setDepthCheckEnabled(false); - pass->setDepthWriteEnabled(false); + //pass->setDepthCheckEnabled(false); + pass->setDepthWriteEnabled(false); + std::cout << "alpha 237; material: " << name << " texName: " << texName << std::endl; + } } else warn("Unhandled alpha setting for texture " + texName); diff --git a/components/nifoverrides/nifoverrides.cpp b/components/nifoverrides/nifoverrides.cpp new file mode 100644 index 000000000..1c8fefd24 --- /dev/null +++ b/components/nifoverrides/nifoverrides.cpp @@ -0,0 +1,37 @@ +#include "nifoverrides.hpp" + +#include + +#include + +using namespace NifOverrides; + +Ogre::ConfigFile Overrides::mTransparencyOverrides = Ogre::ConfigFile(); + +void Overrides::loadTransparencyOverrides (const std::string& file) +{ + mTransparencyOverrides.load(file); +} + +TransparencyResult Overrides::getTransparencyOverride(const std::string& texture) +{ + TransparencyResult result; + result.first = false; + + std::string tex = texture; + boost::to_lower(tex); + + Ogre::ConfigFile::SectionIterator seci = mTransparencyOverrides.getSectionIterator(); + while (seci.hasMoreElements()) + { + Ogre::String sectionName = seci.peekNextKey(); + if (sectionName == tex) + { + result.first = true; + result.second = Ogre::StringConverter::parseInt(mTransparencyOverrides.getSetting("alphaRejectValue", sectionName)); + break; + } + seci.getNext(); + } + return result; +} diff --git a/components/nifoverrides/nifoverrides.hpp b/components/nifoverrides/nifoverrides.hpp new file mode 100644 index 000000000..c9b711df6 --- /dev/null +++ b/components/nifoverrides/nifoverrides.hpp @@ -0,0 +1,23 @@ +#ifndef COMPONENTS_NIFOVERRIDES_H +#define COMPONENTS_NIFOVERRIDES_H + +#include + +namespace NifOverrides +{ + + typedef std::pair TransparencyResult; + + /// \brief provide overrides for some model / texture properties that bethesda has chosen poorly + class Overrides + { + public: + static Ogre::ConfigFile mTransparencyOverrides; + void loadTransparencyOverrides (const std::string& file); + + static TransparencyResult getTransparencyOverride(const std::string& texture); + }; + +} + +#endif diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg new file mode 100644 index 000000000..7750e9834 --- /dev/null +++ b/files/transparency-overrides.cfg @@ -0,0 +1,86 @@ +# Bethesda has used wrong transparency settings for many textures +# (who would have guessed) +# This is very unfortunate because objects with real transparency: +# - cannot cast shadows +# - cannot receive advanced framebuffer effects like depth of field or ambient occlusion +# - cannot cover lens flare effects (the lens flare will just shine through) + +# This file lists textures that should be using alpha rejection instead of transparency +# basically these are textures that are not translucent (i.e. at one spot on the texture, either transparent or opaque) + +# Note: all the texture names here have to be lowercase + +[textures\tx_flag_imp_01.dds] + alphaRejectValue = 128 + +[textures\tx_ivy_02.dds] + alphaRejectValue = 128 + +[textures\tx_ivy_01.dds] + alphaRejectValue = 128 + +[textures\tx_sail.dds] + alphaRejectValue = 128 + +[textures\tx_saltrice_04.dds] + alphaRejectValue = 128 + +[textures\tx_black_lichen_01.dds] + alphaRejectValue = 128 + +[textures\tx_leaves_01.dds] + alphaRejectValue = 128 + +[textures\tx_leaves_02.dds] + alphaRejectValue = 128 + +[textures\tx_leaves_03.dds] + alphaRejectValue = 128 + +[textures\tx_ai_heather_01.dds] + alphaRejectValue = 96 + +[textures\tx_goldkanet_01.dds] + alphaRejectValue = 128 + +[textures\tx_goldkanet_02.dds] + alphaRejectValue = 128 + +[textures\tx_plant_tails00.dds] + alphaRejectValue = 128 + +[textures\tx_vine_01.dds] + alphaRejectValue = 128 + +[textures\tx_comberry_01.dds] + alphaRejectValue = 128 + +[textures\tx_willow_flower_02.dds] + alphaRejectValue = 128 + +[textures\tx_cork_bulb_02.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_telvanni_01.dds] + alphaRejectValue = 128 + +[textures\tx_green_lichen_01.dds] + alphaRejectValue = 128 + +[textures\tx_roobrush_01.dds] + alphaRejectValue = 128 + +[textures\tx_bittergreen_02.dds] + alphaRejectValue = 128 + +[textures\tx_chokeweed_01.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_book_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_w_a_shop_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_temple_02.dds] + alphaRejectValue = 128 From 7fce57f335133735760262849e431adacfc6aba2 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Wed, 11 Apr 2012 20:16:22 -0400 Subject: [PATCH 118/185] Getting started with a new branch --- apps/openmw/mwrender/npcanimation.cpp | 167 ++++++------------------- apps/openmw/mwrender/npcanimation.hpp | 15 +-- apps/openmw/mwworld/inventorystore.cpp | 2 +- components/esm/loadarmo.cpp | 1 + components/esm/loadclot.cpp | 1 + 5 files changed, 50 insertions(+), 136 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8097afdbf..f04ac7609 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,7 +12,7 @@ NpcAnimation::~NpcAnimation(){ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv){ +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ ESMS::LiveCellRef *ref = ptr.get(); Ogre::Entity* blank = 0; @@ -121,6 +121,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); else insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); + std::cout << "Inv" << inv.getStateId() << "\n"; updateParts(); } @@ -133,134 +134,43 @@ void NpcAnimation::updateParts(){ mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ + //A robe was added or removed + if(chest.first) + { + insert->detachObject(chest.first); chest.first = 0; + } + robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); + if(robe != inv.end()) + { + MWWorld::Ptr ptr = *robe; + + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + for(int i = 0; i < parts.size(); i++) + { + ESM::PartReference part = parts[i]; + if(part.part == ESM::PRT_Cuirass) + { + const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + chest = insertFreePart("meshes\\" + bodypart->model, ":\""); + } + } + } - MWWorld::ContainerStoreIterator robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - - + } + if(robe == inv.end() ){ + //if(inv.getSlot(MWWorld::InventoryStore::Cuirass) != inv.end()) + if(chest.first == 0){ + const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); + chest = insertFreePart("meshes\\" + chestPart->model, ":\""); + } + + } - // ; - const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); - const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); - const ESM::BodyPart *groinpart = 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 *neckpart = 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 *feetpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); - const ESM::BodyPart *tailpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail"); - const ESM::BodyPart *wristlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two - const ESM::BodyPart *forearmlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two - const ESM::BodyPart *handlpart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two - const ESM::BodyPart *hairpart = mEnvironment.mWorld->getStore().bodyParts.search(hairID); - const ESM::BodyPart *headpart = mEnvironment.mWorld->getStore().bodyParts.search(headID); - if(bodyRaceID == "b_n_argonian_f_") - forearmlpart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two - if(!handlpart) - handlpart = 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* handrpart = handlpart; - const ESM::BodyPart* forearmr = forearmlpart; - const ESM::BodyPart* wristrpart = wristlpart; - const ESM::BodyPart* armr = arml; - - - if(upperleg){ - lUpperLeg = insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg"); - rUpperLeg = insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg"); - - } - if(foot){ - if(bodyRaceID.compare("b_n_khajiit_m_") == 0) - { - feetpart = foot; - } - else - { - rfoot = insertBoundedPart("meshes\\" + foot->model, "Right Foot"); - lfoot = insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot"); - } - } - if(groinpart){ - groin = insertBoundedPart("meshes\\" + groinpart->model, "Groin"); - } - if(knee) - { - lKnee = insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e - rKnee = insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e - - } - if(ankle){ - - lAnkle = insertBoundedPart("meshes\\" + ankle->model + "*|", "Left Ankle"); //Ogre::Quaternion(Ogre::Radian(3.14 / 4), Ogre::Vector3(1, 0, 0)),blank); //1,0,0, blank); - rAnkle = insertBoundedPart("meshes\\" + ankle->model, "Right Ankle"); - } - if (armr){ - rupperArm = insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm"); - } - if(arml){ - lupperArm = insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm"); - } - - if (forearmr) - { - rForearm = insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm"); - } - if(forearmlpart) - lForearm = insertBoundedPart("meshes\\" + forearmlpart->model + "*|", "Left Forearm"); - - if (wristrpart) - { - rWrist = insertBoundedPart("meshes\\" + wristrpart->model, "Right Wrist"); - } - - if(wristlpart) - lWrist = insertBoundedPart("meshes\\" + wristlpart->model + "*|", "Left Wrist"); - - - - - - /*if(claviclel) - insertBoundedPart("meshes\\" + claviclel->model + "*|", "Left Clavicle", base); - if(clavicler) - insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/ - - if(neckpart) - { - neck = insertBoundedPart("meshes\\" + neckpart->model, "Neck"); - } - if(headpart) - head = insertBoundedPart("meshes\\" + headpart->model, "Head"); - if(hairpart) - hair = insertBoundedPart("meshes\\" + hairpart->model, "Head"); - - if (chestPart){ - chest = insertFreePart("meshes\\" + chestPart->model, ":\""); - - - } - if (handrpart){ - rhand = insertFreePart("meshes\\" + handrpart->model , ":?"); - - } - if (handlpart){ - lhand = insertFreePart("meshes\\" + handlpart->model, ":>"); - - } - if(tailpart){ - tail = insertFreePart("meshes\\" + tailpart->model, ":*"); - } - if(feetpart){ - - lBeastFoot = insertFreePart("meshes\\" + feetpart->model,"::"); - rBeastFoot = insertFreePart("meshes\\" + feetpart->model,":<"); - } - //originalpos = insert->_getWorl } Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ @@ -295,13 +205,14 @@ std::pair*> NpcAnimation::insert void NpcAnimation::runAnimation(float timepassed){ - if(mStateID != inv.getStateId()){ - std::cout << "StateID" < .2){ + timeToChange = 0; + + updateParts(); } - + timeToChange += timepassed; //1. Add the amount of time passed to time diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e90bea5c9..02b161b99 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -15,6 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" +#include "components/esm/loadarmo.hpp" namespace MWRender{ @@ -30,12 +31,11 @@ private: std::pair*> tail; std::pair*> lBeastFoot; std::pair*> rBeastFoot; - /*Ogre::Entity* skirt; std::vector* skirtShapes; - Ogre::Entity* rhand; std::vector* rhandShapes; - Ogre::Entity* lhand; std::vector* lhandShapes; - Ogre::Entity* tail; std::vector* tailShapes; - Ogre::Entity* lBeastFoot; std::vector* lBeastFootShapes; - Ogre::Entity* rBeastFoot; std::vector* rBeastFootShapes;*/ + + int partslots[27]; //Each part slot is taken by clothing, armor, or is empty + + + //Bounded Parts Ogre::Entity* lclavicle; @@ -64,7 +64,8 @@ private: std::string hairID; std::string npcName; std::string bodyRaceID; - + float timeToChange; + MWWorld::ContainerStoreIterator robe; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 650418201..230f7d69a 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -72,7 +72,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite /// \todo restack item previously in this slot (if required) /// \todo unstack item pointed to by iterator if required) - + mSlots[slot] = iterator; flagAsModified(); diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index ddc25e176..8b559b10f 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -11,6 +11,7 @@ void PartReferenceList::load(ESMReader &esm) esm.getHT(pr.part); // The INDX byte pr.male = esm.getHNOString("BNAM"); pr.female = esm.getHNOString("CNAM"); + parts.push_back(pr); } } diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 1d6c9d4a1..16fd0598c 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -13,6 +13,7 @@ void Clothing::load(ESMReader &esm) icon = esm.getHNOString("ITEX"); parts.load(esm); + enchant = esm.getHNOString("ENAM"); } From 800df7376ccc1b88c56c286af5e7a1fe1e12c091 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 14:26:21 +0200 Subject: [PATCH 119/185] use the cursors from morrowind.bsa and remove mwpointer.png --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 4 ++++ apps/openmw/mwgui/cursorreplace.cpp | 16 ++++++++++++++++ apps/openmw/mwgui/cursorreplace.hpp | 16 ++++++++++++++++ files/mygui/CMakeLists.txt | 1 - files/mygui/mwpointer.png | Bin 4810 -> 0 bytes files/mygui/openmw_images.xml | 18 +++++++++--------- libs/openengine/ogre/imagerotate.cpp | 3 +-- libs/openengine/ogre/imagerotate.hpp | 2 +- 9 files changed, 48 insertions(+), 14 deletions(-) create mode 100644 apps/openmw/mwgui/cursorreplace.cpp create mode 100644 apps/openmw/mwgui/cursorreplace.hpp delete mode 100644 files/mygui/mwpointer.png diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a8ae0bd49..b417c764d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui layouts text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base + map_window window_pinnable_base cursorreplace ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 259733600..8fe6963a9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -28,6 +28,7 @@ #include "mwinput/inputmanager.hpp" #include "mwgui/window_manager.hpp" +#include "mwgui/cursorreplace.hpp" #include "mwscript/scriptmanager.hpp" #include "mwscript/compilercontext.hpp" @@ -368,6 +369,9 @@ void OMW::Engine::go() loadBSA(); + // cursor replacer (converts the cursor from the bsa so they can be used by mygui) + MWGui::CursorReplace replacer; + // Create the world mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster, mResDir, mNewGame, mEnvironment, mEncoding, mFallbackMap); diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp new file mode 100644 index 000000000..2079538fc --- /dev/null +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -0,0 +1,16 @@ +#include "cursorreplace.hpp" + +#include +#include + +#include +#include + +using namespace MWGui; + +CursorReplace::CursorReplace() +{ + OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); + OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); + OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); +} diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp new file mode 100644 index 000000000..06fe28e39 --- /dev/null +++ b/apps/openmw/mwgui/cursorreplace.hpp @@ -0,0 +1,16 @@ +#ifndef GAME_CURSORREPLACE_H +#define GAME_CURSORREPLACE_H + +#include + +namespace MWGui +{ + /// \brief MyGUI does not support rotating cursors, so we have to do it manually + class CursorReplace + { + public: + CursorReplace(); + }; +} + +#endif diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index dbc20f3f8..e3a7b9999 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -8,7 +8,6 @@ configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY) configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY) configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY) configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" COPYONLY) -configure_file("${SDIR}/mwpointer.png" "${DDIR}/mwpointer.png" COPYONLY) configure_file("${SDIR}/mwgui.png" "${DDIR}/mwgui.png" COPYONLY) configure_file("${SDIR}/openmw_images.xml" "${DDIR}/openmw_images.xml" COPYONLY) configure_file("${SDIR}/openmw_settings.xml" "${DDIR}/openmw_settings.xml" COPYONLY) diff --git a/files/mygui/mwpointer.png b/files/mygui/mwpointer.png deleted file mode 100644 index 90bc19b5e2c7ea4f30b895cc5b8cde00ce460e98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4810 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 diff --git a/files/mygui/openmw_images.xml b/files/mygui/openmw_images.xml index 6487742c3..e149273e2 100644 --- a/files/mygui/openmw_images.xml +++ b/files/mygui/openmw_images.xml @@ -2,37 +2,37 @@ - + - + - + - + - + - + - + - + - + diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index 166a1d3c6..b7522c100 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -49,7 +49,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest unsigned int height = sourceTexture->getHeight(); TexturePtr destTexture = TextureManager::getSingleton().createManual( - "ImageRotateDestTexture", + destImage, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, width, height, @@ -69,7 +69,6 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest rtt->writeContentsToFile(destImage); // remove all the junk we've created - TextureManager::getSingleton().remove("ImageRotateDestTexture"); MaterialManager::getSingleton().remove("ImageRotateMaterial"); root->destroySceneManager(sceneMgr); delete rect; diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp index 85363d71f..a3f6d662f 100644 --- a/libs/openengine/ogre/imagerotate.hpp +++ b/libs/openengine/ogre/imagerotate.hpp @@ -15,7 +15,7 @@ namespace Render public: /** * @param source image (file name - has to exist in an resource group) - * @param destination image (absolute file path) + * @param name of the destination texture to save to (in memory) * @param angle in degrees to turn */ static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); From 4a6a8e5420eb24f203d6645b157e3aba63a21342 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 14:28:35 +0200 Subject: [PATCH 120/185] don't write to disk --- libs/openengine/ogre/imagerotate.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index b7522c100..1147559d6 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -66,7 +66,6 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest vp->setClearEveryFrame(true, FBT_DEPTH); rtt->update(); - rtt->writeContentsToFile(destImage); // remove all the junk we've created MaterialManager::getSingleton().remove("ImageRotateMaterial"); From 2b8c81e7795a01c00a6e014714d31206abaa0af4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 14:31:12 +0200 Subject: [PATCH 121/185] removed test.skin file --- files/mygui/test.skin | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 files/mygui/test.skin diff --git a/files/mygui/test.skin b/files/mygui/test.skin deleted file mode 100644 index 5f198ab4a..000000000 --- a/files/mygui/test.skin +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From 95f87a8abf437e7cc0e35c77c785ca619f02b6dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 16:33:36 +0200 Subject: [PATCH 122/185] more or less complete list for morrowind.bsa (thanks to artorius) --- components/nifogre/ogre_nif_loader.cpp | 2 +- files/transparency-overrides.cfg | 502 ++++++++++++++++++++++++- 2 files changed, 496 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 6f5142796..ab6a708c0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -296,7 +296,7 @@ void NIFLoader::createMaterial(const String &name, //pass->setDepthCheckEnabled(false); pass->setDepthWriteEnabled(false); - std::cout << "alpha 237; material: " << name << " texName: " << texName << std::endl; + //std::cout << "alpha 237; material: " << name << " texName: " << texName << std::endl; } } else diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg index 7750e9834..299792be1 100644 --- a/files/transparency-overrides.cfg +++ b/files/transparency-overrides.cfg @@ -10,16 +10,23 @@ # Note: all the texture names here have to be lowercase -[textures\tx_flag_imp_01.dds] +# fauna +[textures\tx_wickwheat_01.dds] alphaRejectValue = 128 -[textures\tx_ivy_02.dds] +[textures\tx_wickwheat_03.dds] alphaRejectValue = 128 -[textures\tx_ivy_01.dds] +[textures\tx_red_lichen_01.dds] alphaRejectValue = 128 -[textures\tx_sail.dds] +[textures\tx_stone_flower_01.dds] + alphaRejectValue = 128 + +[textures\tx_ivy_02.dds] + alphaRejectValue = 128 + +[textures\tx_ivy_01.dds] alphaRejectValue = 128 [textures\tx_saltrice_04.dds] @@ -37,6 +44,15 @@ [textures\tx_leaves_03.dds] alphaRejectValue = 128 +[textures\tx_leaves_04.dds] + alphaRejectValue = 128 + +[textures\tx_leaves_06.dds] + alphaRejectValue = 128 + +[textures\tx_leaves_07.dds] + alphaRejectValue = 128 + [textures\tx_ai_heather_01.dds] alphaRejectValue = 96 @@ -61,9 +77,6 @@ [textures\tx_cork_bulb_02.dds] alphaRejectValue = 128 -[textures\tx_v_b_telvanni_01.dds] - alphaRejectValue = 128 - [textures\tx_green_lichen_01.dds] alphaRejectValue = 128 @@ -76,11 +89,486 @@ [textures\tx_chokeweed_01.dds] alphaRejectValue = 128 +[textures\tx_branches_01.dds] + alphaRejectValue = 128 + +[textures\tx_branches_02.dds] + alphaRejectValue = 128 + +[textures\tx_guarskin_hut_03.dds] + alphaRejectValue = 128 + +[textures\tx_hackle-lo_02.dds] + alphaRejectValue = 128 + +[textures\tx_bc_fern_01.dds] + alphaRejectValue = 128 + +[textures\tx_bc_fern_02.dds] + alphaRejectValue = 128 + +[textures\tx_bc_leaves_02.dds] + alphaRejectValue = 128 + +[textures\tx_marshmerrow_03.dds] + alphaRejectValue = 128 + +[textures\tx_bc_moss_01.dds] + alphaRejectValue = 128 + +[textures\tx_bc_moss_02.dds] + alphaRejectValue = 128 + +[textures\tx_bc_lilypad_01.dds] + alphaRejectValue = 128 + +[textures\tx_bc_lilypad_02.dds] + alphaRejectValue = 128 + +[textures\tx_bc_lilypad_03.dds] + alphaRejectValue = 128 + +[textures\tx_fire_fern_01.dds] + alphaRejectValue = 128 + +# banners and flags +[textures\tx_flag_imp_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_arena_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_comfort_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_child_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_count_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_faith_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_walk_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_imp_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_redoran_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_avs_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_serving_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_speak_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_stdeyln_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_stolms_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_thin_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_vivec_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_vivec_02.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_01.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_02.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_04.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_05.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_06.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_banner_07.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_a_banner.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_e_banner.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_u_banner.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_z_banner.dds] + alphaRejectValue = 128 + +[textures\tx_banner_6th.dds] + alphaRejectValue = 128 + +[textures\tx_banner_6th_tall.dds] + alphaRejectValue = 128 + +[textures\tx_banner_gnisis_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_gnisis_02.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_bhm_01.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_02.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_03.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_04.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_05.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_06.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_07.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_08.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_08.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_09.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_10.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_11.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_12.dds] + alphaRejectValue = 128 + +[textures\tx_de_tapestry_13.dds] + alphaRejectValue = 128 + +[textures\tx_de_lutestrings_01.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_imp_altar_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_akatosh_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_apprentice_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_arkay_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_dibella_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_golem_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_julianos_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_kynareth_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_lady_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_lord_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_lover_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_mara_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_ritual_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_shadow_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_steed_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_stendarr_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_thief_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_tower_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_warrior_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_wizard_01.dds] + alphaRejectValue = 128 + +[textures\tx_c_t_zenithar_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_dagoth_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_tavern_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_goods_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_danger_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_welcome_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_clothing_01.dds] + alphaRejectValue = 128 + +[textures\tx_bannerd_alchemy_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_hlaalu_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_redoran_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_temple_01.dds] + alphaRejectValue = 128 + +[textures\tx_banner_temple_03.dds] + alphaRejectValue = 128 + [textures\tx_de_banner_book_01.dds] alphaRejectValue = 128 +[textures\tx_de_banner_ald_velothi.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_gnaar_mok.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_hla_oad.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_khull.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_pawn_01.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_sadrith_mora.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_tel_aruhn.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_tel_branora.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_tel_fyr.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_tel_mora.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_telvani_01.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_tel_vos.dds] + alphaRejectValue = 128 + +[textures\tx_de_banner_vos.dds] + alphaRejectValue = 128 + [textures\tx_bannerd_w_a_shop_01.dds] alphaRejectValue = 128 [textures\tx_banner_temple_02.dds] alphaRejectValue = 128 + +[textures\tx_mural1_00.dds] + alphaRejectValue = 128 + +[textures\tx_mural1_01.dds] + alphaRejectValue = 128 + +[textures\tx_mural4_00.dds] + alphaRejectValue = 128 + +[textures\tx_mural4_01.dds] + alphaRejectValue = 128 + +[textures\tx_mural5_00.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_telvanni_01.dds] + alphaRejectValue = 128 + +[textures\tx_v_b_hlaalu_01.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_tapestry.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_tapestry_01.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_tapestry_02.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_tapestry_03.dds] + alphaRejectValue = 128 + +[textures\tx_fabric_tapestry_04.dds] + alphaRejectValue = 128 + +# characters +[textures\tx_netchgod00.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_argonian_f_hair02.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_argonian_f_hair03.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_argonian_m_hair01.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_argonian_m_hair04.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_argonian_m_hair05.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_khajiit_f_hair01.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_khajiit_f_hair02.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_khajiit_m_hair01.dds] + alphaRejectValue = 128 + +[textures\tx_corprus_stalker12.dds] + alphaRejectValue = 128 + +[textures\tx_a_clavicus02.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_dark elf_m_hair11.dds] + alphaRejectValue = 128 + +[textures\tx_b_n_dark elf_f_hair10.dds] + alphaRejectValue = 128 + +# misc items +[textures\tx_sail.dds] + alphaRejectValue = 128 + +[textures\tx_longboatsail01.dds] + alphaRejectValue = 128 + +[textures\tx_longboatsail01a.dds] + alphaRejectValue = 128 + +[textures\tx_longboatsail01b.dds] + alphaRejectValue = 128 + +[textures\tx_longboatsail02.dds] + alphaRejectValue = 128 + +[textures\tx_quill.dds] + alphaRejectValue = 128 + +[textures\tx_note_01.dds] + alphaRejectValue = 128 + +[textures\tx_note_02.dds] + alphaRejectValue = 128 + +[textures\tx_parchment_02.dds] + alphaRejectValue = 128 + +[textures\tx_parchment_03.dds] + alphaRejectValue = 128 + +[textures\tx_scroll_01.dds] + alphaRejectValue = 128 + +[textures\tx_scroll_02.dds] + alphaRejectValue = 128 + +[textures\tx_scroll_03.dds] + alphaRejectValue = 128 + +[textures\tx_alpha_small_edge.dds] + alphaRejectValue = 128 + +[textures\tx_alpha_shadow_circular.dds] + alphaRejectValue = 128 + +# building materials +[textures\tx_shack_thatch_strip.dds] + alphaRejectValue = 128 + +[textures\tx_rug00.dds] + alphaRejectValue = 128 + +[textures\tx_rug_02.dds] + alphaRejectValue = 128 + +[textures\tx_rug_edge_01.dds] + alphaRejectValue = 128 + +[textures\tx_awning_thatch_02.dds] + alphaRejectValue = 128 + +[textures\tx_awning_woven_01.dds] + alphaRejectValue = 128 + +[textures\tx_bridgeropes.dds] + alphaRejectValue = 128 + +[textures\tx_rope_woven_01.dds] + alphaRejectValue = 128 + +[textures\tx_rope_woven_02.dds] + alphaRejectValue = 128 + +[textures\tx_ashl_tent_06.dds] + alphaRejectValue = 128 + +[textures\tx_guar_tarp.dds] + alphaRejectValue = 128 + +[textures\tx_velothi_glyph00.dds] + alphaRejectValue = 128 From a96ad7fb8295df3470dd0b008d978d234317edd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 16:46:56 +0200 Subject: [PATCH 123/185] restored toggleWater --- apps/openmw/mwrender/water.cpp | 55 +++++++++++++++++----------------- apps/openmw/mwrender/water.hpp | 2 ++ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 85fb2ee99..71cf56dfd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -11,7 +11,7 @@ namespace MWRender Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), - mReflectionTarget(0), mActive(1) + mReflectionTarget(0), mActive(1), mToggled(1) { mSky = sky; @@ -93,32 +93,32 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : // destroy if already exists if (overlay = mgr.getByName("ReflectionDebugOverlay")) mgr.destroy(overlay); - + overlay = mgr.create("ReflectionDebugOverlay"); - + if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/ReflectionDebugTexture", + "Ogre/ReflectionDebugTexture", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - + debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); OverlayContainer* debugPanel; - + // destroy container if exists try { - if (debugPanel = + if (debugPanel = static_cast( mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" ))) mgr.destroyOverlayElement(debugPanel); } catch (Ogre::Exception&) {} - + debugPanel = (OverlayContainer*) (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel")); debugPanel->_setPosition(0, 0.55); @@ -134,8 +134,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : void Water::setActive(bool active) { mActive = active; - if (mReflectionTarget) mReflectionTarget->setActive(active && !mIsUnderwater); - mWater->setVisible(active); + updateVisible(); } Water::~Water() @@ -167,8 +166,8 @@ void Water::setHeight(const float height) void Water::toggle() { - if (mActive) - mWater->setVisible(!mWater->getVisible()); + mToggled = !mToggled; + updateVisible(); } void Water::checkUnderwater(float y) @@ -183,13 +182,10 @@ void Water::checkUnderwater(float y) if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0)); - if (mReflectionTarget) - mReflectionTarget->setActive(mActive); - mWater->setRenderQueueGroup(RQG_Water); mIsUnderwater = false; - } + } if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { @@ -201,13 +197,12 @@ void Water::checkUnderwater(float y) if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1)); - if (mReflectionTarget) - mReflectionTarget->setActive(false); - mWater->setRenderQueueGroup(RQG_UnderWater); mIsUnderwater = true; } + + updateVisible(); } Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) @@ -217,15 +212,14 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) { - mReflectionCamera->setOrientation(mCamera->getDerivedOrientation()); - mReflectionCamera->setPosition(mCamera->getDerivedPosition()); - mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); - mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); - mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); - mReflectionCamera->setFOVy(mCamera->getFOVy()); if (evt.source == mReflectionTarget) { - mWater->setVisible(false); + mReflectionCamera->setOrientation(mCamera->getDerivedOrientation()); + mReflectionCamera->setPosition(mCamera->getDerivedPosition()); + mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); + mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); + mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); + mReflectionCamera->setFOVy(mCamera->getFOVy()); // Some messy code to get the skybox to show up at all // The problem here is that it gets clipped by the water plane @@ -242,8 +236,6 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { - mWater->setVisible(true); - if (evt.source == mReflectionTarget) { mSky->resetSkyPosition(); @@ -291,4 +283,11 @@ void Water::setViewportBackground(const ColourValue& bg) mReflectionTarget->getViewport(0)->setBackgroundColour(bg); } +void Water::updateVisible() +{ + mWater->setVisible(mToggled && mActive); + if (mReflectionTarget) + mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 3fb1b07b7..f14482e2b 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -24,6 +24,7 @@ namespace MWRender { bool mIsUnderwater; bool mActive; + bool mToggled; int mTop; Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); @@ -31,6 +32,7 @@ namespace MWRender { protected: void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void updateVisible(); SkyManager* mSky; From 03d6d1fb82faf7dcdd808facfcefb7e2716b8cfc Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 12 Apr 2012 17:08:57 +0200 Subject: [PATCH 124/185] NPC rank is correctly loaded now. Also corrected a potential bug (i think). --- apps/openmw/mwclass/npc.cpp | 45 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b98df79ef..43e04ab52 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -55,31 +55,38 @@ namespace MWClass { if(ref->base->npdt52.gold != -10) { - data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank; + data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank; } else { - data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank; + data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank; } } - for (int i=0; i<27; ++i) - data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); - - // creature stats - data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); - data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); - data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower); - data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility); - data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed); - data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance); - data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality); - data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck); - data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health); - data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana); - data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue); - - data->mCreatureStats.mLevel = ref->base->npdt52.level; + if(ref->base->npdt52.gold != -10) + { + for (int i=0; i<27; ++i) + data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); + + // creature stats + data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); + data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); + data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower); + data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility); + data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed); + data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance); + data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality); + data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck); + data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health); + data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana); + data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue); + + data->mCreatureStats.mLevel = ref->base->npdt52.level; + } + else + { + //TODO: do something with npdt12 maybe:p + } // \todo add initial container content From 7edc5c733ca0f52bcba0025a5dc5244c8e1dff09 Mon Sep 17 00:00:00 2001 From: gugus Date: Thu, 12 Apr 2012 17:29:05 +0200 Subject: [PATCH 125/185] corrected a bug about rank. --- apps/openmw/mwdialogue/dialoguemanager.cpp | 4 ++-- apps/openmw/mwscript/statsextensions.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 140522499..90f0c0231 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -488,7 +488,7 @@ namespace MWDialogue if(it!=stats.mFactionRank.end()) { //check rank - if(it->second < info.data.rank) return false; + if(it->second < (int)info.data.rank) return false; } else { @@ -505,7 +505,7 @@ namespace MWDialogue if(it!=stats.mFactionRank.end()) { //check rank - if(it->second < info.data.rank) return false; + if(it->second < (int)info.data.PCrank) return false; } else { diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index a3c517f8c..47ae9d13d 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -307,7 +307,7 @@ namespace MWScript MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; } else { @@ -340,7 +340,7 @@ namespace MWScript MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 1; + MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; } else { From e2ec889d1008bd721a945330b136a53a0950a6b0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 17:40:26 +0200 Subject: [PATCH 126/185] fixed a warning "implicit cast to float3" --- apps/openmw/mwrender/shaderhelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp index 93f960dc4..5354251f8 100644 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -258,7 +258,7 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s outStream << " float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" - " oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour, fogValue); \n" + " oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour.xyz, fogValue); \n" " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << From fb78e853d41f07158705936213f21dd1804d0b16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 12 Apr 2012 19:18:38 +0200 Subject: [PATCH 127/185] removed 2 unneeded lines --- apps/openmw/mwrender/shadows.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 9c150f0c6..bf5602f43 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -55,9 +55,7 @@ void Shadows::recreate() mSceneMgr->setShadowCasterRenderBackFaces(true); mSceneMgr->setShadowTextureCasterMaterial("depth_shadow_caster"); mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); - mSceneMgr->setShadowDirLightTextureOffset(0.9); mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - mSceneMgr->setShowDebugShadows(true); mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows"); mSceneMgr->setShadowFarDistance(mShadowFar); From a885f3e9422646e1212d0b0344ed4205918b63ed Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Thu, 12 Apr 2012 20:40:11 -0400 Subject: [PATCH 128/185] Remove part function --- apps/openmw/mwrender/npcanimation.cpp | 158 +++++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 5 +- 2 files changed, 161 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f04ac7609..520cc12bb 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,11 +12,32 @@ NpcAnimation::~NpcAnimation(){ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), + robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), + lclavicle(0), + rclavicle(0), + rupperArm(0), + lupperArm(0), + rUpperLeg(0), + lUpperLeg(0), + lForearm(0), + rForearm(0), + lWrist(0), + rWrist(0), + rKnee(0), + lKnee(0), + neck(0), + rAnkle(0), + lAnkle(0), + groin(0), + lfoot(0), + rfoot(0) + { ESMS::LiveCellRef *ref = ptr.get(); Ogre::Entity* blank = 0; std::vector* blankshape = 0; + zero = std::make_pair(blank, blankshape); chest = std::make_pair(blank, blankshape); tail = std::make_pair(blank, blankshape); lBeastFoot = std::make_pair(blank, blankshape); @@ -24,6 +45,12 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O rhand = std::make_pair(blank, blankshape); lhand = std::make_pair(blank, blankshape); skirt = std::make_pair(blank, blankshape); + for (int init = 0; init < 27; init++){ + partslots[init] = -1; //each slot is empty + partpriorities[init] = 0; + } + + //Part selection on last character of the file string // " Tri Chest // * Tri Tail @@ -254,4 +281,133 @@ void NpcAnimation::runAnimation(float timepassed){ } } + +void NpcAnimation::removeIndividualPart(int type){ + partpriorities[type] = 0; + partslots[type] = -1; + + if(type == ESM::PRT_Head && head){ //0 + base->detachObjectFromBone(head); + head = 0; + } + else if(type == ESM::PRT_Hair && hair){//1 + base->detachObjectFromBone(hair); + hair = 0; + } + else if(type == ESM::PRT_Neck && neck){//2 + base->detachObjectFromBone(neck); + neck = 0; + } + else if(type == ESM::PRT_Cuirass && chest.first){//3 + insert->detachObject(chest.first); + chest = zero; + } + else if(type == ESM::PRT_Groin && groin){//4 + base->detachObjectFromBone(groin); + groin = 0; + } + else if(type == ESM::PRT_Skirt && skirt.first){//5 + insert->detachObject(skirt.first); + skirt = zero; + } + else if(type == ESM::PRT_RHand && rhand.first){//6 + insert->detachObject(rhand.first); + rhand = zero; + } + else if(type == ESM::PRT_LHand && lhand.first){//7 + insert->detachObject(lhand.first); + lhand = zero; + } + else if(type == ESM::PRT_RWrist && rWrist){//8 + base->detachObjectFromBone(rWrist); + rWrist = 0; + } + else if(type == ESM::PRT_LWrist && lWrist){//9 + base->detachObjectFromBone(lWrist); + lWrist = 0; + } + else if(type == ESM::PRT_Shield){//10 + + } + else if(type == ESM::PRT_RForearm && rForearm){//11 + base->detachObjectFromBone(rForearm); + rForearm = 0; + } + else if(type == ESM::PRT_LForearm && lForearm){//12 + base->detachObjectFromBone(lForearm); + lForearm = 0; + } + else if(type == ESM::PRT_RUpperarm && rupperArm){//13 + base->detachObjectFromBone(rupperArm); + rupperArm = 0; + } + else if(type == ESM::PRT_LUpperarm && lupperArm){//14 + base->detachObjectFromBone(lupperArm); + lupperArm = 0; + } + else if(type == ESM::PRT_RFoot){ //15 + if(rfoot){ + base->detachObjectFromBone(rfoot); + rfoot = 0; + } + else if(rBeastFoot.first){ + insert->detachObject(rBeastFoot.first); + rBeastFoot = zero; + } + } + else if(type == ESM::PRT_LFoot){ //16 + if(lfoot){ + base->detachObjectFromBone(lfoot); + lfoot = 0; + } + else if(lBeastFoot.first){ + insert->detachObject(lBeastFoot.first); + lBeastFoot = zero; + } + } + else if(type == ESM::PRT_RAnkle && rAnkle){ //17 + base->detachObjectFromBone(rAnkle); + rAnkle = 0; + } + else if(type == ESM::PRT_LAnkle && lAnkle){ //18 + base->detachObjectFromBone(lAnkle); + lAnkle = 0; + } + else if(type == ESM::PRT_RKnee && rKnee){ //19 + base->detachObjectFromBone(rKnee); + rKnee = 0; + } + else if(type == ESM::PRT_LKnee && lKnee){ //20 + base->detachObjectFromBone(lKnee); + lKnee = 0; + } + else if(type == ESM::PRT_RLeg && rUpperLeg){ //21 + base->detachObjectFromBone(rAnkle); + rUpperLeg = 0; + } + else if(type == ESM::PRT_LLeg && lUpperLeg){ //22 + base->detachObjectFromBone(lUpperLeg); + lUpperLeg = 0; + } + else if(type == ESM::PRT_RPauldron && rclavicle){ //23 + base->detachObjectFromBone(rclavicle); + rclavicle = 0; + } + else if(type == ESM::PRT_LPauldron && lclavicle){ //24 + base->detachObjectFromBone(lclavicle); + lclavicle = 0; + } + else if(type == ESM::PRT_Weapon){ //25 + + } + else if(type == ESM::PRT_Tail && tail.first){ //26 + insert->detachObject(tail.first); + tail = zero; + } + + + + + } + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 02b161b99..eecb598df 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -33,7 +33,8 @@ private: std::pair*> rBeastFoot; int partslots[27]; //Each part slot is taken by clothing, armor, or is empty - + int partpriorities[27]; + std::pair*> zero; @@ -58,6 +59,7 @@ private: Ogre::Entity* rfoot; Ogre::Entity* hair; Ogre::Entity* head; + Ogre::SceneNode* insert; bool isBeast; std::string headID; @@ -74,6 +76,7 @@ private: std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); virtual void runAnimation(float timepassed); void updateParts(); + void removeIndividualPart(int type); }; } From 1f566fc93a66e1cfc7b2516e9937dd88c53c3e40 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Thu, 12 Apr 2012 20:59:30 -0400 Subject: [PATCH 129/185] Another remove function --- apps/openmw/mwrender/npcanimation.cpp | 9 +++++++++ apps/openmw/mwrender/npcanimation.hpp | 1 + 2 files changed, 10 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 520cc12bb..0b546bf13 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -410,4 +410,13 @@ void NpcAnimation::removeIndividualPart(int type){ } + void NpcAnimation::removePartGroup(int group){ + for(int i = 0; i < 27; i++){ + if(partslots[i] == group){ + removeIndividualPart(i); + } + } + } } + + diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index eecb598df..0b4442e3a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -77,6 +77,7 @@ private: virtual void runAnimation(float timepassed); void updateParts(); void removeIndividualPart(int type); + void removePartGroup(int group); }; } From e869433b07c0e30cbd73affeb64b8d551484d7b6 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Thu, 12 Apr 2012 22:16:02 -0400 Subject: [PATCH 130/185] Add or replace individual parts --- apps/openmw/mwrender/npcanimation.cpp | 100 +++++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 1 + 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0b546bf13..37e3573f8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -382,7 +382,7 @@ void NpcAnimation::removeIndividualPart(int type){ lKnee = 0; } else if(type == ESM::PRT_RLeg && rUpperLeg){ //21 - base->detachObjectFromBone(rAnkle); + base->detachObjectFromBone(rUpperLeg); rUpperLeg = 0; } else if(type == ESM::PRT_LLeg && lUpperLeg){ //22 @@ -417,6 +417,104 @@ void NpcAnimation::removeIndividualPart(int type){ } } } + bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh){ + if(priority >= partpriorities[type]){ + removeIndividualPart(type); + partslots[type] = group; + switch(type){ + case ESM::PRT_Head: //0 + head = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Hair: //1 + hair = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Neck: //2 + neck = insertBoundedPart(mesh, "Neck"); + break; + case ESM::PRT_Cuirass: //3 + chest = insertFreePart(mesh, ":\""); + break; + case ESM::PRT_Groin: //4 + neck = insertBoundedPart(mesh, "Groin"); + break; + case ESM::PRT_Skirt: //5 + skirt = insertFreePart(mesh, ":|"); + break; + case ESM::PRT_RHand: //6 + rhand = insertFreePart(mesh, ":?"); + break; + case ESM::PRT_LHand: //7 + lhand = insertFreePart(mesh, ":>"); + break; + case ESM::PRT_RWrist: //8 + rWrist = insertBoundedPart(mesh, "Right Wrist"); + break; + case ESM::PRT_LWrist: //9 + lWrist = insertBoundedPart(mesh + "*|", "Left Wrist"); + break; + case ESM::PRT_Shield: //10 + break; + case ESM::PRT_RForearm: //11 + rForearm = insertBoundedPart(mesh, "Right Forearm"); + break; + case ESM::PRT_LForearm: //12 + lForearm = insertBoundedPart(mesh + "*|", "Left Forearm"); + break; + case ESM::PRT_RUpperarm: //13 + rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); + break; + case ESM::PRT_LUpperarm: //14 + lupperArm = insertBoundedPart(mesh + "*|", "Left Upper Arm"); + break; + case ESM::PRT_RFoot: //15 + if(isBeast) + rBeastFoot = insertFreePart(mesh, ":<"); + else + rfoot = insertBoundedPart(mesh, "Right Foot"); + break; + case ESM::PRT_LFoot: //16 + if(isBeast) + lBeastFoot = insertFreePart(mesh, "::"); + else + lfoot = insertBoundedPart(mesh + "*|", "Left Foot"); + break; + + case ESM::PRT_RAnkle: //17 + rAnkle = insertBoundedPart(mesh , "Right Ankle"); + break; + case ESM::PRT_LAnkle: //18 + lAnkle = insertBoundedPart(mesh + "*|", "Left Ankle"); + break; + case ESM::PRT_RKnee: //19 + rKnee = insertBoundedPart(mesh , "Right Knee"); + break; + case ESM::PRT_LKnee: //20 + lKnee = insertBoundedPart(mesh + "*|", "Left Knee"); + break; + case ESM::PRT_RLeg: //21 + rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); + break; + case ESM::PRT_LLeg: //22 + lUpperLeg = insertBoundedPart(mesh + "*|", "Left Upper Leg"); + break; + case ESM::PRT_RPauldron: //23 + rclavicle = insertBoundedPart(mesh , "Right Clavicle"); + break; + case ESM::PRT_LPauldron: //24 + lclavicle = insertBoundedPart(mesh + "*|", "Left Clavicle"); + break; + case ESM::PRT_Weapon: //25 + break; + case ESM::PRT_Tail: //26 + tail = insertFreePart(mesh, ":*"); + break; + + + } + return true; + } + return false; + } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 0b4442e3a..e5858e38c 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -78,6 +78,7 @@ private: void updateParts(); void removeIndividualPart(int type); void removePartGroup(int group); + bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); }; } From 52c7ee3b6ae8a9738289a1728cb02ad8d9a49e1f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Apr 2012 10:49:45 +0200 Subject: [PATCH 131/185] moved selected spell from NpcStats to Spells --- apps/openmw/mwmechanics/npcstats.hpp | 5 ++--- apps/openmw/mwmechanics/spells.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/spells.hpp | 11 ++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index ece85f893..b9c672722 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -12,7 +12,8 @@ namespace MWMechanics /// /// For non-NPC-specific stats, see the CreatureStats struct. /// - /// \note For technical reasons the spell list is also handled by CreatureStats. + /// \note For technical reasons the spell list and the currently selected spell is also handled by + /// CreatureStats, even though they are actually NPC stats. struct NpcStats { @@ -28,8 +29,6 @@ namespace MWMechanics bool mSneak; bool mCombat; - std::string mSelectedSpell; // can be an empty string (no spell selected) - NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), mCombat (false) {} }; diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 4e8c6fa5a..916239a84 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -43,6 +43,9 @@ namespace MWMechanics if (iter!=mSpells.end()) mSpells.erase (iter); + + if (spellId==mSelectedSpell) + mSelectedSpell.clear(); } MagicEffects Spells::getMagicEffects (const MWWorld::Environment& environment) const @@ -65,4 +68,14 @@ namespace MWMechanics { mSpells.clear(); } + + void Spells::setSelectedSpell (const std::string& spellId) + { + mSelectedSpell = spellId; + } + + const std::string Spells::getSelectedSpell() const + { + return mSelectedSpell; + } } diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 4c5f21d35..f7606c4ac 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -32,6 +32,7 @@ namespace MWMechanics private: std::vector mSpells; + std::string mSelectedSpell; void addSpell (const ESM::Spell *, MagicEffects& effects) const; @@ -42,15 +43,23 @@ namespace MWMechanics TIterator end() const; void add (const std::string& spell); - /// \note Adding a spell that is already listed in *this is a no-op. + ///< Adding a spell that is already listed in *this is a no-op. void remove (const std::string& spell); + ///< If the spell to be removed is the selected spell, the selected spell will be changed to + /// no spell (empty string). MagicEffects getMagicEffects (const MWWorld::Environment& environment) const; ///< Return sum of magic effects resulting from abilities, blights, deseases and curses. void clear(); ///< Remove all spells of al types. + + void setSelectedSpell (const std::string& spellId); + ///< This function does not verify, if the spell is available. + + const std::string getSelectedSpell() const; + ///< May return an empty string. }; } From b099e1baf583202cbaed50697011d09d50a72dc0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Apr 2012 11:12:53 +0200 Subject: [PATCH 132/185] added addspell and removespell script instructions --- apps/openmw/mwscript/docs/vmformat.txt | 6 ++- apps/openmw/mwscript/statsextensions.cpp | 47 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index df955ec19..705d65814 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -129,4 +129,8 @@ op 0x2000143: ModWaterLevel op 0x2000144: ToggleWater, twa op 0x2000145: ToggleFogOfWar (tfow) op 0x2000146: TogglePathgrid -opcodes 0x2000147-0x3ffffff unused +op 0x2000147: AddSpell +op 0x2000148: AddSpell, explicit reference +op 0x2000149: RemoveSpell +op 0x200014a: RemoveSpell, explicit reference +opcodes 0x200014b-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 0e97a39cf..10641903e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -280,6 +280,38 @@ namespace MWScript } }; + template + class OpAddSpell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.add (id); + } + }; + + template + class OpRemoveSpell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.remove (id); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -311,6 +343,11 @@ namespace MWScript const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; + const int opcodeAddSpell = 0x2000147; + const int opcodeAddSpellExplicit = 0x2000148; + const int opcodeRemoveSpell = 0x2000149; + const int opcodeRemoveSpellExplicit = 0x200014a; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -381,6 +418,10 @@ namespace MWScript extensions.registerInstruction (mod + skills[i], "l", opcodeModSkill+i, opcodeModSkillExplicit+i); } + + extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); + extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, + opcodeRemoveSpellExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -436,6 +477,12 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill (i)); interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } + + interpreter.installSegment5 (opcodeAddSpell, new OpAddSpell); + interpreter.installSegment5 (opcodeAddSpellExplicit, new OpAddSpell); + interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell); + interpreter.installSegment5 (opcodeRemoveSpellExplicit, + new OpRemoveSpell); } } } From e3486931aef62a4d10eff259a6fb1fd71e488d7d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Apr 2012 13:17:50 +0200 Subject: [PATCH 133/185] F10 hotkey toggle FPS --- apps/openmw/mwgui/layouts.cpp | 35 +++++++++++++++++++--------- apps/openmw/mwgui/layouts.hpp | 1 + apps/openmw/mwgui/window_manager.cpp | 10 ++++++++ apps/openmw/mwgui/window_manager.hpp | 5 +++- apps/openmw/mwinput/inputmanager.cpp | 10 ++++++++ 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/layouts.cpp index 6d8aa901b..21302d7c1 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/layouts.cpp @@ -67,17 +67,8 @@ HUD::HUD(int width, int height, int fpsLevel) getWidget(crosshair, "Crosshair"); - if ( fpsLevel == 2 ){ - getWidget(fpsbox, "FPSBoxAdv"); - fpsbox->setVisible(true); - getWidget(fpscounter, "FPSCounterAdv"); - }else if ( fpsLevel == 1 ){ - getWidget(fpsbox, "FPSBox"); - fpsbox->setVisible(true); - getWidget(fpscounter, "FPSCounter"); - }else{ - getWidget(fpscounter, "FPSCounter"); - } + setFpsLevel(fpsLevel); + getWidget(trianglecounter, "TriangleCounter"); getWidget(batchcounter, "BatchCounter"); @@ -95,6 +86,28 @@ HUD::HUD(int width, int height, int fpsLevel) LocalMapBase::init(minimap, this); } +void HUD::setFpsLevel(int level) +{ + MyGUI::Widget* fps; + getWidget(fps, "FPSBoxAdv"); + fps->setVisible(false); + getWidget(fps, "FPSBox"); + fps->setVisible(false); + + if (level == 2) + { + getWidget(fpsbox, "FPSBoxAdv"); + fpsbox->setVisible(true); + getWidget(fpscounter, "FPSCounterAdv"); + } + else if (level == 1) + { + getWidget(fpsbox, "FPSBox"); + fpsbox->setVisible(true); + getWidget(fpscounter, "FPSCounter"); + } +} + void HUD::setFPS(float fps) { fpscounter->setCaption(boost::lexical_cast((int)fps)); diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp index 0614708cf..19d96d2ef 100644 --- a/apps/openmw/mwgui/layouts.hpp +++ b/apps/openmw/mwgui/layouts.hpp @@ -78,6 +78,7 @@ namespace MWGui void setPlayerPos(const float x, const float y); void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); + void setFpsLevel(const int level); MyGUI::ProgressPtr health, magicka, stamina; MyGUI::Widget *weapBox, *spellBox; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 13b6fab31..34d62ba08 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -15,6 +15,8 @@ #include "journalwindow.hpp" #include "charactercreation.hpp" +#include + #include #include #include @@ -472,3 +474,11 @@ void WindowManager::toggleFogOfWar() map->toggleFogOfWar(); hud->toggleFogOfWar(); } + +int WindowManager::toggleFps() +{ + showFPSLevel = (showFPSLevel+1)%3; + hud->setFpsLevel(showFPSLevel); + Settings::Manager::setInt("fps", "HUD", showFPSLevel); + return showFPSLevel; +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index f1db11731..2b53560ba 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -158,7 +158,10 @@ namespace MWGui void setPlayerDir(const float x, const float y); ///< set player view direction in map space void toggleFogOfWar(); - + + int toggleFps(); + ///< toggle fps display @return resulting fps level + void setInteriorMapTexture(const int x, const int y); ///< set the index of the map texture that should be used (for interiors) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index bd27de029..9b5a9ae30 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -68,6 +68,8 @@ namespace MWInput A_ToggleWeapon, A_ToggleSpell, + A_ToggleFps, // Toggle FPS display (this is temporary) + A_LAST // Marker for the last item }; @@ -88,6 +90,11 @@ namespace MWInput /* InputImpl Methods */ + void toggleFps() + { + windows.toggleFps(); + } + void toggleSpell() { DrawState state = player.getDrawState(); @@ -235,6 +242,8 @@ namespace MWInput "Draw Weapon"); disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), "Ready hands"); + disp->funcs.bind(A_ToggleFps, boost::bind(&InputImpl::toggleFps, this), + "Toggle FPS display"); // Add the exit listener ogre.getRoot()->addFrameListener(&exit); @@ -281,6 +290,7 @@ namespace MWInput disp->bind(A_ToggleWalk, KC_C); disp->bind(A_ToggleWeapon,KC_F); disp->bind(A_ToggleSpell,KC_R); + disp->bind(A_ToggleFps, KC_F10); // Key bindings for polled keys // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. From e16daeed238c140754642388ffa6d7988884382e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Apr 2012 13:17:57 +0200 Subject: [PATCH 134/185] added GetSpell script function --- apps/openmw/mwscript/docs/vmformat.txt | 4 ++- apps/openmw/mwscript/statsextensions.cpp | 32 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 705d65814..1317794fa 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -133,4 +133,6 @@ op 0x2000147: AddSpell op 0x2000148: AddSpell, explicit reference op 0x2000149: RemoveSpell op 0x200014a: RemoveSpell, explicit reference -opcodes 0x200014b-0x3ffffff unused +op 0x200014b: GetSpell +op 0x200014c: GetSpell, explicit reference +opcodes 0x200014d-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 10641903e..011b8b010 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -312,6 +312,33 @@ namespace MWScript } }; + template + class OpGetSpell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer value = 0; + + for (MWMechanics::Spells::TIterator iter ( + MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.begin()); + iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.end(); ++iter) + if (*iter==id) + { + value = 1; + break; + } + + runtime.push (value); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -347,6 +374,8 @@ namespace MWScript const int opcodeAddSpellExplicit = 0x2000148; const int opcodeRemoveSpell = 0x2000149; const int opcodeRemoveSpellExplicit = 0x200014a; + const int opcodeGetSpell = 0x200014b; + const int opcodeGetSpellExplicit = 0x200014c; void registerExtensions (Compiler::Extensions& extensions) { @@ -422,6 +451,7 @@ namespace MWScript extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); + extensions.registerFunction ("getspell", 'l', "c", opcodeGetSpell, opcodeGetSpellExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -483,6 +513,8 @@ namespace MWScript interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell); interpreter.installSegment5 (opcodeRemoveSpellExplicit, new OpRemoveSpell); + interpreter.installSegment5 (opcodeGetSpell, new OpGetSpell); + interpreter.installSegment5 (opcodeGetSpellExplicit, new OpGetSpell); } } } From a33ae35e9487913454e87797425307375dc8aefb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Apr 2012 13:28:31 +0200 Subject: [PATCH 135/185] some fixes --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwrender/terrainmaterial.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ee60407b2..984b7ddc9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -56,6 +56,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); if (caps->getNumMultiRenderTargets() < 2) Settings::Manager::setBool("shader", "Water", false); + if (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_4_0")) + Settings::Manager::setBool("enabled", "Shadows", false); // note that the order is important here if (useMRT()) @@ -108,7 +110,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const RenderingManager::~RenderingManager () { - //TODO: destroy mSun? delete mPlayer; delete mSkyManager; delete mDebugging; diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 57bea5388..c69ed3a61 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -1339,7 +1339,13 @@ namespace Ogre // diffuse lighting for (int i=0; igetNumberOfLightsSupported(); ++i) + { + // shadows only for first light (directional) + if (i==0) outStream << " outputCol.rgb += litRes"<isLayerSpecularMappingEnabled()) From 3442ef17a8ee4dc37d74f63dcd0c95843179ab2b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 13 Apr 2012 14:54:13 +0200 Subject: [PATCH 136/185] fixed ModDisposition --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/statsextensions.cpp | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 17f11d3a9..fda8d1954 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -139,4 +139,5 @@ op 0x200014a: RemoveSpell, explicit reference op 0x200014b: GetSpell op 0x200014c: GetSpell, explicit reference op 0x200014d: ModDisposition -opcodes 0x200014e-0x3ffffff unused +op 0x200014e: ModDisposition, explicit reference +opcodes 0x200014f-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index f7a4e5d86..9d3009870 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -435,13 +435,19 @@ namespace MWScript } }; + template class OpModDisposition : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr ptr = R()(runtime); + +// Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + /// \todo modify disposition towards the player } }; @@ -487,6 +493,7 @@ namespace MWScript const int opcodePCLowerRank = 0x2000c; const int opcodePCJoinFaction = 0x2000d; const int opcodeModDisposition = 0x200014d; + const int opcodeModDispositionExplicit = 0x200014e; void registerExtensions (Compiler::Extensions& extensions) { @@ -567,7 +574,8 @@ namespace MWScript extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); - extensions.registerInstruction("moddisposition","l",opcodeModDisposition); + extensions.registerInstruction("moddisposition","l",opcodeModDisposition, + opcodeModDispositionExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -635,7 +643,8 @@ namespace MWScript interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); - interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); + interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); + interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); } } } From 0c6862e3e6469ade34ed6d994ffa92e2bcc90ff3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 13 Apr 2012 15:09:38 +0200 Subject: [PATCH 137/185] Undefining some windows defines --- apps/openmw/mwmechanics/drawstate.hpp | 2 ++ apps/openmw/mwrender/terrainmaterial.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/drawstate.hpp b/apps/openmw/mwmechanics/drawstate.hpp index ded25f8d5..772086d90 100644 --- a/apps/openmw/mwmechanics/drawstate.hpp +++ b/apps/openmw/mwmechanics/drawstate.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_DRAWSTATE_H #define GAME_MWMECHANICS_DRAWSTATE_H +#undef DrawState + enum DrawState { DrawState_Weapon = 0, diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 57bea5388..331bb47e3 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -39,6 +39,8 @@ THE SOFTWARE. #include #include "renderingmanager.hpp" +#undef far + namespace Ogre { //--------------------------------------------------------------------- From 226f312163593db2d46dce2c1886b8b365e03650 Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 13 Apr 2012 17:36:31 +0200 Subject: [PATCH 138/185] Set the version in the openmw.desktop file via CMake --- CMakeLists.txt | 3 +++ files/openmw.desktop | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3ca740af..286d0f743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -244,6 +244,9 @@ endif (WIN32) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux "${OpenMW_BINARY_DIR}/plugins.cfg") + + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop + "${OpenMW_BINARY_DIR}/openmw.desktop") endif() if (APPLE) diff --git a/files/openmw.desktop b/files/openmw.desktop index 8643d4b13..234f660c6 100644 --- a/files/openmw.desktop +++ b/files/openmw.desktop @@ -1,5 +1,5 @@ [Desktop Entry] -Version=0.11 +Version=${OPENMW_VERSION} Type=Application Name=OpenMW Launcher GenericName=Role Playing Game From dc2751f4ec40cec649797e76c7e002a371d965fb Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 13 Apr 2012 17:39:46 +0200 Subject: [PATCH 139/185] Moved Build options to the top. I need this for my tar.gz packages but i think this is a good idea in general. --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 286d0f743..d67d3eb5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,11 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_ option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) +# Apps and tools +option(BUILD_ESMTOOL "build ESM inspector" ON) +option(BUILD_LAUNCHER "build Launcher" ON) +option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) + # Sound source selection option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_AUDIERE "use audiere for sound" OFF) @@ -416,17 +421,14 @@ add_subdirectory (components) # Apps and tools add_subdirectory( apps/openmw ) -option(BUILD_ESMTOOL "build ESM inspector" ON) if (BUILD_ESMTOOL) add_subdirectory( apps/esmtool ) endif() -option(BUILD_LAUNCHER "build Launcher inspector" ON) if (BUILD_LAUNCHER) add_subdirectory( apps/launcher ) endif() -option(BUILD_MWINIIMPORTER "build MWiniImporter inspector" ON) if (BUILD_MWINIIMPORTER) add_subdirectory( apps/mwiniimporter ) endif() From 2d6cd162966f69501ebc8c5f428f8ca4fa382400 Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 13 Apr 2012 17:53:01 +0200 Subject: [PATCH 140/185] Now Debian Packages install the configured openmw.desktop file. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d67d3eb5f..9969747d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,7 +315,7 @@ if(DPKG_PROGRAM) endif() #Install icon and desktop file - INSTALL(FILES "${OpenMW_SOURCE_DIR}/files/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/files/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install global configuration files From 8156e9e5c4022db029213f04e5e62eb8958dac8a Mon Sep 17 00:00:00 2001 From: k1ll Date: Fri, 13 Apr 2012 18:20:49 +0200 Subject: [PATCH 141/185] Fixed install search path for openmw.desktop. It's directly in the binary dir. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9969747d3..442710a02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,7 +315,7 @@ if(DPKG_PROGRAM) endif() #Install icon and desktop file - INSTALL(FILES "${OpenMW_BINARY_DIR}/files/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "share/applications/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "share/pixmaps/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install global configuration files From 52b0b28c78f1423c463cfbb390bb1a1f3f6d2161 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 13 Apr 2012 19:20:59 +0200 Subject: [PATCH 142/185] fixed the mygui output on console --- libs/openengine/gui/manager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 2d84ac804..1bf8ec325 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -18,7 +18,6 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // manager before the main gui system itself, otherwise the main // object will get the chance to spit out a few messages before we // can able to disable it. - /// \todo - can't avoid this with MyGUI 3.2? std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); if(!logDir.empty()) @@ -26,9 +25,9 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform. We might make this more generic later. mPlatform = new OgrePlatform(); + LogManager::getInstance().setSTDOutputEnabled(logging); mPlatform->initialise(wnd, mgr, "General", theLogFile); - LogManager::getInstance().setSTDOutputEnabled(logging); // Create GUI mGui = new Gui(); From 7551926afd698109527cd76888bbb8a8f567750e Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Fri, 13 Apr 2012 23:25:15 -0400 Subject: [PATCH 143/185] Adding helmets --- apps/openmw/mwrender/npcanimation.cpp | 56 +++++++++++++++++++-------- apps/openmw/mwrender/npcanimation.hpp | 1 + 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 37e3573f8..34dbb0862 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -13,7 +13,7 @@ NpcAnimation::~NpcAnimation(){ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), - robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), + robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), lclavicle(0), rclavicle(0), rupperArm(0), @@ -160,13 +160,12 @@ void NpcAnimation::updateParts(){ std::string hairModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; + + //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ //A robe was added or removed - if(chest.first) - { - insert->detachObject(chest.first); chest.first = 0; - } + removePartGroup(MWWorld::InventoryStore::Slot_Robe); robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); if(robe != inv.end()) { @@ -177,23 +176,47 @@ void NpcAnimation::updateParts(){ for(int i = 0; i < parts.size(); i++) { ESM::PartReference part = parts[i]; - if(part.part == ESM::PRT_Cuirass) - { + const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - chest = insertFreePart("meshes\\" + bodypart->model, ":\""); - } + if(bodypart) + addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Robe,5,"meshes\\" + bodypart->model); + } } } - if(robe == inv.end() ){ - //if(inv.getSlot(MWWorld::InventoryStore::Cuirass) != inv.end()) - if(chest.first == 0){ - const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); - chest = insertFreePart("meshes\\" + chestPart->model, ":\""); + if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ + helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); + removePartGroup(MWWorld::InventoryStore::Slot_Helmet); + removeIndividualPart(ESM::PRT_Hair); + if(helmet != inv.end()){ + const ESM::Armor *armor = (helmet->get())->base; + std::vector parts = armor->parts.parts; + for(int i = 0; i < parts.size(); i++) + { + ESM::PartReference part = parts[i]; + + const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + if(bodypart) + addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Helmet,3,"meshes\\" + bodypart->model); + + } } - + } + + if(partpriorities[ESM::PRT_Cuirass] < 1){ + const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); + if(chestPart) + addOrReplaceIndividualPart(ESM::PRT_Cuirass, -1,1,"meshes\\" + chestPart->model); + } + if(partpriorities[ESM::PRT_Head] < 1){ + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1,headModel); + } + if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1){ + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); + } + @@ -418,9 +441,10 @@ void NpcAnimation::removeIndividualPart(int type){ } } bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh){ - if(priority >= partpriorities[type]){ + if(priority > partpriorities[type]){ removeIndividualPart(type); partslots[type] = group; + partpriorities[type] = priority; switch(type){ case ESM::PRT_Head: //0 head = insertBoundedPart(mesh, "Head"); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e5858e38c..b3d9b3c4a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -68,6 +68,7 @@ private: std::string bodyRaceID; float timeToChange; MWWorld::ContainerStoreIterator robe; + MWWorld::ContainerStoreIterator helmet; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); From e04d127f30817dfbe02eebe9cc65f358515cfe59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Apr 2012 15:10:26 +0200 Subject: [PATCH 144/185] terrain shader fixes --- apps/openmw/mwrender/terrainmaterial.cpp | 68 +++++++++--------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 331bb47e3..7ed2a703b 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -540,7 +540,6 @@ namespace Ogre params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX); params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM, Terrain::LOD_MORPH_CUSTOM_PARAM); - params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); if (prof->isShadowingEnabled(tt, terrain)) { @@ -576,7 +575,7 @@ namespace Ogre { params->setNamedAutoConstant("lightPosObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i); params->setNamedAutoConstant("lightDiffuseColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i); - if (prof->getNumberOfLightsSupported() > 1) + if (i > 0) params->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); //params->setNamedAutoConstant("lightSpecularColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, i); } @@ -586,6 +585,7 @@ namespace Ogre params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); + params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); if (prof->isShadowingEnabled(tt, terrain)) { @@ -813,11 +813,11 @@ namespace Ogre outStream << "out float4 oPos : POSITION,\n" - "out float4 oPosObj : COLOR \n"; + "out float4 oPosObj : TEXCOORD0 \n"; - uint texCoordSet = 0; + uint texCoordSet = 1; outStream << - ", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n"; + ", out float4 oUVMisc : COLOR0 // xy = uv, z = camDepth\n"; // layer UV's premultiplied, packed as xy/zw uint numUVSets = numLayers / 2; @@ -837,14 +837,6 @@ namespace Ogre outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n"; } - bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; - if (fog) - { - outStream << - ", uniform float4 fogParams\n"; - //", out float fogVal : COLOR\n"; - } - if (prof->isShadowingEnabled(tt, terrain)) { texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream); @@ -940,11 +932,11 @@ namespace Ogre outStream << "void main_fp(\n" - "float4 position : COLOR,\n"; + "float4 position : TEXCOORD0,\n"; - uint texCoordSet = 0; + uint texCoordSet = 1; outStream << - "float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n"; + "float4 uvMisc : COLOR0,\n"; // UV's premultiplied, packed as xy/zw uint maxLayers = prof->getMaxLayers(terrain); @@ -971,8 +963,8 @@ namespace Ogre if (fog) { outStream << + "uniform float4 fogParams, \n" "uniform float3 fogColour, \n"; - //"float fogVal : COLOR,\n"; } uint currentSamplerIdx = 0; @@ -991,7 +983,7 @@ namespace Ogre //"uniform float3 lightSpecularColour"<getNumberOfLightsSupported() > 1) + if (i > 0) outStream << "uniform float4 lightAttenuation"<getNumberOfLightsSupported() > 1) + if (i > 0) outStream << // pre-multiply light color with attenuation factor "d = length( lightDir"<getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; - if (fog) - { - if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) - { - outStream << - " float fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n"; - } - else - { - outStream << - " float fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n"; - } - outStream << - " oPosObj.w = fogVal; \n"; - } + " oPosObj.w = oPos.z;\n"; if (prof->isShadowingEnabled(tt, terrain)) generateVpDynamicShadows(prof, terrain, tt, outStream); @@ -1369,6 +1343,16 @@ namespace Ogre bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; if (fog) { + if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) + { + outStream << + " float fogVal = saturate((position.w - fogParams.y) * fogParams.w);\n"; + } + else + { + outStream << + " float fogVal = saturate(1 / (exp(position.w * fogParams.x)));\n"; + } outStream << " outputCol.rgb = lerp(outputCol.rgb, fogColour, fogVal);\n"; } @@ -1376,7 +1360,7 @@ namespace Ogre outStream << " oColor = outputCol;\n"; if (MWRender::RenderingManager::useMRT()) outStream << - " oColor1 = float4(uvMisc.z / far, 0, 0, 1); \n"; + " oColor1 = float4(position.w / far, 0, 0, 1); \n"; outStream << "}\n"; @@ -1585,7 +1569,7 @@ namespace Ogre { uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); outStream << - " float camDepth = uvMisc.z;\n"; + " float camDepth = position.w;\n"; if (prof->getReceiveDynamicShadowsDepth()) { @@ -1629,8 +1613,8 @@ namespace Ogre outStream << " float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n" - " float fade = 1-((uvMisc.z - shadowFar_fadeStart.y) / fadeRange); \n" - " rtshadow = (uvMisc.z > shadowFar_fadeStart.x) ? 1 : ((uvMisc.z > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n" + " float fade = 1-((position.w - shadowFar_fadeStart.y) / fadeRange); \n" + " rtshadow = (position.w > shadowFar_fadeStart.x) ? 1 : ((position.w > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n" " rtshadow = (1-(1-rtshadow)*0.6); \n" // make the shadow a little less intensive " shadow = min(shadow, rtshadow);\n"; From fa5a1432c9817238245be20ec3ee17ec3107c3f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Apr 2012 15:58:58 +0200 Subject: [PATCH 145/185] map lighting tweak, default settings tweak --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ files/settings-default.cfg | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 984b7ddc9..c1462807f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -482,11 +482,13 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) void RenderingManager::disableLights() { mObjects.disableLights(); + sunDisable(); } void RenderingManager::enableLights() { mObjects.enableLights(); + sunEnable(); } const bool RenderingManager::useMRT() diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4d2d46fca..553a82e49 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -93,7 +93,7 @@ rtt size = 512 reflect terrain = true reflect statics = false reflect small statics = false -reflect actors = true +reflect actors = false reflect misc = false # Enable underwater effect. It is not resource intensive, so only disable it if you have problems. From 4b0099fb5b1c90214a14e0d387d52a2ed2668c0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 14 Apr 2012 16:10:47 +0200 Subject: [PATCH 146/185] npc visibility flags fix --- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9de5705e3..a231e8fe7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -240,6 +240,7 @@ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::stri NIFLoader::load(mesh); Entity* ent = mRend.getScene()->createEntity(mesh); + ent->setVisibilityFlags(RV_Actors); base->attachObjectToBone(bonename, ent); return ent; @@ -249,9 +250,7 @@ void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suf NIFLoader::load(meshNumbered); Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered); - - - + ent->setVisibilityFlags(RV_Actors); insert->attachObject(ent); entityparts.push_back(ent); From 5d4ad4cd810501e09f2b6550fb4e28204ebe8223 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 14 Apr 2012 16:44:46 -0400 Subject: [PATCH 147/185] Shirts and Cuirasses --- apps/openmw/mwclass/clothing.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 68 ++++++++++++++++++++++----- apps/openmw/mwrender/npcanimation.hpp | 2 + 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 1fbc11c63..672a2b60a 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -89,7 +89,7 @@ namespace MWClass static const int sMapping[size][2] = { - { ESM::Clothing::Shirt, MWWorld::InventoryStore::Slot_Cuirass }, + { ESM::Clothing::Shirt, MWWorld::InventoryStore::Slot_Shirt }, { ESM::Clothing::Belt, MWWorld::InventoryStore::Slot_Belt }, { ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe }, { ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants }, diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 34dbb0862..08c53f39d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -13,7 +13,8 @@ NpcAnimation::~NpcAnimation(){ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), - robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), + robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), shirt(inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)), + cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), lclavicle(0), rclavicle(0), rupperArm(0), @@ -159,7 +160,7 @@ void NpcAnimation::updateParts(){ std::string hairModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; - + bool apparelChanged = false; //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); @@ -167,7 +168,31 @@ void NpcAnimation::updateParts(){ //A robe was added or removed removePartGroup(MWWorld::InventoryStore::Slot_Robe); robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - if(robe != inv.end()) + apparelChanged = true; + + + } + if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ + apparelChanged = true; + helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); + removePartGroup(MWWorld::InventoryStore::Slot_Helmet); + + } + if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)){ + cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); + removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); + apparelChanged = true; + + } + if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ + shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); + removePartGroup(MWWorld::InventoryStore::Slot_Shirt); + apparelChanged = true; + + } + + if(apparelChanged){ + if(robe != inv.end()) { MWWorld::Ptr ptr = *robe; @@ -183,13 +208,9 @@ void NpcAnimation::updateParts(){ } } - - } - if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ - helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); - removePartGroup(MWWorld::InventoryStore::Slot_Helmet); - removeIndividualPart(ESM::PRT_Hair); - if(helmet != inv.end()){ + + if(helmet != inv.end()){ + removeIndividualPart(ESM::PRT_Hair); const ESM::Armor *armor = (helmet->get())->base; std::vector parts = armor->parts.parts; for(int i = 0; i < parts.size(); i++) @@ -202,7 +223,32 @@ void NpcAnimation::updateParts(){ } } - + if(cuirass != inv.end()){ + const ESM::Armor *armor = (cuirass->get())->base; + std::vector parts = armor->parts.parts; + for(int i = 0; i < parts.size(); i++) + { + ESM::PartReference part = parts[i]; + + const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + if(bodypart) + addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Cuirass,3,"meshes\\" + bodypart->model); + + } + } + if(shirt != inv.end()){ + const ESM::Clothing *clothes = (shirt->get())->base; + std::vector parts = clothes->parts.parts; + for(int i = 0; i < parts.size(); i++) + { + ESM::PartReference part = parts[i]; + + const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + if(bodypart) + addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Shirt,2,"meshes\\" + bodypart->model); + + } + } } if(partpriorities[ESM::PRT_Cuirass] < 1){ diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b3d9b3c4a..377560222 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -69,6 +69,8 @@ private: float timeToChange; MWWorld::ContainerStoreIterator robe; MWWorld::ContainerStoreIterator helmet; + MWWorld::ContainerStoreIterator shirt; + MWWorld::ContainerStoreIterator cuirass; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); From e5becb1f50dc79b14a5f587629516ee216ab6f95 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 14 Apr 2012 18:58:52 -0400 Subject: [PATCH 148/185] Group add function;Greaves --- apps/openmw/mwrender/npcanimation.cpp | 81 ++++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 6 +- 2 files changed, 47 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 08c53f39d..bacee7f2d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -14,7 +14,7 @@ NpcAnimation::~NpcAnimation(){ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), shirt(inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)), - cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), + cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), greaves(inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)), lclavicle(0), rclavicle(0), rupperArm(0), @@ -79,7 +79,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2); - bool female = tolower(secondtolast) == 'f'; + isFemale = tolower(secondtolast) == 'f'; std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); isBeast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; @@ -145,7 +145,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insert->attachObject(base); - if(female) + if(isFemale) 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); @@ -183,6 +183,12 @@ void NpcAnimation::updateParts(){ removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); apparelChanged = true; + } + if(greaves != inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)){ + cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); + removePartGroup(MWWorld::InventoryStore::Slot_Greaves); + apparelChanged = true; + } if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); @@ -198,56 +204,32 @@ void NpcAnimation::updateParts(){ const ESM::Clothing *clothes = (ptr.get())->base; std::vector parts = clothes->parts.parts; - for(int i = 0; i < parts.size(); i++) - { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) - addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Robe,5,"meshes\\" + bodypart->model); - - } + addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); } if(helmet != inv.end()){ removeIndividualPart(ESM::PRT_Hair); const ESM::Armor *armor = (helmet->get())->base; std::vector parts = armor->parts.parts; - for(int i = 0; i < parts.size(); i++) - { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) - addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Helmet,3,"meshes\\" + bodypart->model); - - } + addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); + } if(cuirass != inv.end()){ const ESM::Armor *armor = (cuirass->get())->base; std::vector parts = armor->parts.parts; - for(int i = 0; i < parts.size(); i++) - { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) - addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Cuirass,3,"meshes\\" + bodypart->model); - - } + addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); + + } + if(greaves != inv.end()){ + const ESM::Armor *armor = (greaves->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); + } if(shirt != inv.end()){ const ESM::Clothing *clothes = (shirt->get())->base; std::vector parts = clothes->parts.parts; - for(int i = 0; i < parts.size(); i++) - { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) - addOrReplaceIndividualPart(part.part, MWWorld::InventoryStore::Slot_Shirt,2,"meshes\\" + bodypart->model); - - } + addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } } @@ -299,6 +281,8 @@ std::pair*> NpcAnimation::insert } + + void NpcAnimation::runAnimation(float timepassed){ if(timeToChange > .2){ @@ -585,6 +569,25 @@ void NpcAnimation::removeIndividualPart(int type){ } return false; } + + void NpcAnimation::addPartGroup(int group, int priority, std::vector& parts){ + for(int i = 0; i < parts.size(); i++) + { + ESM::PartReference part = parts[i]; + + + const ESM::BodyPart *bodypart = 0; + + if(isFemale) + bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.female); + if(!bodypart) + bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + + if(bodypart) + addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); + + } + } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 377560222..545634e1f 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -62,6 +62,7 @@ private: Ogre::SceneNode* insert; bool isBeast; + bool isFemale; std::string headID; std::string hairID; std::string npcName; @@ -71,6 +72,7 @@ private: MWWorld::ContainerStoreIterator helmet; MWWorld::ContainerStoreIterator shirt; MWWorld::ContainerStoreIterator cuirass; + MWWorld::ContainerStoreIterator greaves; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); @@ -80,8 +82,10 @@ private: virtual void runAnimation(float timepassed); void updateParts(); void removeIndividualPart(int type); - void removePartGroup(int group); + bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); + void removePartGroup(int group); + void addPartGroup(int group, int priority, std::vector& parts); }; } From 940a90e3baac2f924bcd1fba0de672c9b74a2717 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 14 Apr 2012 19:21:14 -0400 Subject: [PATCH 149/185] Pauldrons --- apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 2 ++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index bacee7f2d..5adb9914d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -15,6 +15,7 @@ NpcAnimation::~NpcAnimation(){ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), shirt(inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)), cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), greaves(inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)), + leftpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)), rightpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)), lclavicle(0), rclavicle(0), rupperArm(0), @@ -185,9 +186,20 @@ void NpcAnimation::updateParts(){ } if(greaves != inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)){ - cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); + greaves = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); removePartGroup(MWWorld::InventoryStore::Slot_Greaves); apparelChanged = true; + } + if(leftpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)){ + leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron); + removePartGroup(MWWorld::InventoryStore::Slot_LeftPauldron); + apparelChanged = true; + + } + if(rightpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)){ + leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); + removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); + apparelChanged = true; } if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ @@ -225,6 +237,18 @@ void NpcAnimation::updateParts(){ std::vector parts = armor->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); + } + if(leftpauldron != inv.end()){ + const ESM::Armor *armor = (leftpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); + + } + if(rightpauldron != inv.end()){ + const ESM::Armor *armor = (rightpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); + } if(shirt != inv.end()){ const ESM::Clothing *clothes = (shirt->get())->base; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 545634e1f..7785ffc1a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -73,6 +73,8 @@ private: MWWorld::ContainerStoreIterator shirt; MWWorld::ContainerStoreIterator cuirass; MWWorld::ContainerStoreIterator greaves; + MWWorld::ContainerStoreIterator leftpauldron; + MWWorld::ContainerStoreIterator rightpauldron; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); From 5e1ac0cca1c8a20095da079065b2fad0aa443fbe Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 14 Apr 2012 20:32:46 -0400 Subject: [PATCH 150/185] Gloves, Gauntlets, Boots, Shoes --- apps/openmw/mwrender/npcanimation.cpp | 71 ++++++++++++++++++++++++++- apps/openmw/mwrender/npcanimation.hpp | 4 ++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5adb9914d..3a9525949 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,6 +16,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), shirt(inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)), cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), greaves(inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)), leftpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)), rightpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)), + boots(inv.getSlot(MWWorld::InventoryStore::Slot_Boots)), + leftglove(inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)), rightglove(inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)), + pants(inv.getSlot(MWWorld::InventoryStore::Slot_Pants)), lclavicle(0), rclavicle(0), rupperArm(0), @@ -197,10 +200,28 @@ void NpcAnimation::updateParts(){ } if(rightpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)){ - leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); + rightpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); apparelChanged = true; + } + if(boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)){ + boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); + removePartGroup(MWWorld::InventoryStore::Slot_Boots); + apparelChanged = true; + + } + if(leftglove != inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)){ + leftglove = inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet); + removePartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet); + apparelChanged = true; + + } + if(rightglove != inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)){ + rightglove = inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet); + removePartGroup(MWWorld::InventoryStore::Slot_RightGauntlet); + apparelChanged = true; + } if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); @@ -210,6 +231,7 @@ void NpcAnimation::updateParts(){ } if(apparelChanged){ + std::cout << "Modifying stuff\n"; if(robe != inv.end()) { MWWorld::Ptr ptr = *robe; @@ -238,6 +260,7 @@ void NpcAnimation::updateParts(){ addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); } + if(leftpauldron != inv.end()){ const ESM::Armor *armor = (leftpauldron->get())->base; std::vector parts = armor->parts.parts; @@ -250,6 +273,52 @@ void NpcAnimation::updateParts(){ addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } + if(boots != inv.end()){ + + if(boots->getTypeName() == "struct ESM::Clothing"){ + const ESM::Clothing *clothes = (boots->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); + } + else + { + const ESM::Armor *armor = (boots->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); + } + + } + if(leftglove != inv.end()){ + + if(leftglove->getTypeName() == "struct ESM::Clothing"){ + const ESM::Clothing *clothes = (leftglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (leftglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); + } + + } + if(rightglove != inv.end()){ + + if(rightglove->getTypeName() == "struct ESM::Clothing"){ + const ESM::Clothing *clothes = (rightglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (rightglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); + } + + } + if(shirt != inv.end()){ const ESM::Clothing *clothes = (shirt->get())->base; std::vector parts = clothes->parts.parts; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 7785ffc1a..255989d28 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -75,6 +75,10 @@ private: MWWorld::ContainerStoreIterator greaves; MWWorld::ContainerStoreIterator leftpauldron; MWWorld::ContainerStoreIterator rightpauldron; + MWWorld::ContainerStoreIterator boots; + MWWorld::ContainerStoreIterator pants; + MWWorld::ContainerStoreIterator leftglove; + MWWorld::ContainerStoreIterator rightglove; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); From 85ac658cacb03ef53455e57ea7b97f41bbab5c36 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sat, 14 Apr 2012 22:52:05 -0400 Subject: [PATCH 151/185] Adding tons of skin body parts --- apps/openmw/mwrender/npcanimation.cpp | 135 ++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 3a9525949..bc134581d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -205,7 +205,7 @@ void NpcAnimation::updateParts(){ apparelChanged = true; } - if(boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)){ + if(!isBeast && boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)){ boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); removePartGroup(MWWorld::InventoryStore::Slot_Boots); apparelChanged = true; @@ -228,6 +228,12 @@ void NpcAnimation::updateParts(){ removePartGroup(MWWorld::InventoryStore::Slot_Shirt); apparelChanged = true; + } + if(pants != inv.getSlot(MWWorld::InventoryStore::Slot_Pants)){ + pants = inv.getSlot(MWWorld::InventoryStore::Slot_Pants); + removePartGroup(MWWorld::InventoryStore::Slot_Pants); + apparelChanged = true; + } if(apparelChanged){ @@ -273,7 +279,7 @@ void NpcAnimation::updateParts(){ addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(boots != inv.end()){ + if(!isBeast && boots != inv.end()){ if(boots->getTypeName() == "struct ESM::Clothing"){ const ESM::Clothing *clothes = (boots->get())->base; @@ -324,19 +330,136 @@ void NpcAnimation::updateParts(){ std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } + if(pants != inv.end()){ + const ESM::Clothing *clothes = (pants->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); + } } + if(partpriorities[ESM::PRT_Head] < 1){ + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1,headModel); + } + if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1){ + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); + } + if(partpriorities[ESM::PRT_Neck] < 1){ + const ESM::BodyPart *neckPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck"); + if(neckPart) + addOrReplaceIndividualPart(ESM::PRT_Neck, -1,1,"meshes\\" + neckPart->model); + } if(partpriorities[ESM::PRT_Cuirass] < 1){ const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); if(chestPart) addOrReplaceIndividualPart(ESM::PRT_Cuirass, -1,1,"meshes\\" + chestPart->model); } - if(partpriorities[ESM::PRT_Head] < 1){ - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1,headModel); + + if(partpriorities[ESM::PRT_Groin] < 1){ + const ESM::BodyPart *groinPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin"); + if(groinPart) + addOrReplaceIndividualPart(ESM::PRT_Groin, -1,1,"meshes\\" + groinPart->model); } - if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1){ - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); + if(partpriorities[ESM::PRT_RHand] < 1){ + const ESM::BodyPart *handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); + if(!handPart) + handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands"); + if(handPart) + addOrReplaceIndividualPart(ESM::PRT_RHand, -1,1,"meshes\\" + handPart->model); + } + if(partpriorities[ESM::PRT_LHand] < 1){ + const ESM::BodyPart *handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); + if(!handPart) + handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands"); + if(handPart) + addOrReplaceIndividualPart(ESM::PRT_LHand, -1,1,"meshes\\" + handPart->model); } + + if(partpriorities[ESM::PRT_RWrist] < 1){ + const ESM::BodyPart *wristPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); + if(wristPart) + addOrReplaceIndividualPart(ESM::PRT_RWrist, -1,1,"meshes\\" + wristPart->model); + } + if(partpriorities[ESM::PRT_LWrist] < 1){ + const ESM::BodyPart *wristPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); + if(wristPart) + addOrReplaceIndividualPart(ESM::PRT_LWrist, -1,1,"meshes\\" + wristPart->model); + } + if(partpriorities[ESM::PRT_RForearm] < 1){ + const ESM::BodyPart *forearmPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); + if(bodyRaceID == "b_n_argonian_f_") + forearmPart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); + if(forearmPart) + addOrReplaceIndividualPart(ESM::PRT_RForearm, -1,1,"meshes\\" + forearmPart->model); + } + if(partpriorities[ESM::PRT_LForearm] < 1){ + const ESM::BodyPart *forearmPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); + if(bodyRaceID == "b_n_argonian_f_") + forearmPart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); + if(forearmPart) + addOrReplaceIndividualPart(ESM::PRT_LForearm, -1,1,"meshes\\" + forearmPart->model); + } + if(partpriorities[ESM::PRT_RUpperarm] < 1){ + const ESM::BodyPart *armPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); + if(armPart) + addOrReplaceIndividualPart(ESM::PRT_RUpperarm, -1,1,"meshes\\" + armPart->model); + } + if(partpriorities[ESM::PRT_LUpperarm] < 1){ + const ESM::BodyPart *armPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); + if(armPart) + addOrReplaceIndividualPart(ESM::PRT_LUpperarm, -1,1,"meshes\\" + armPart->model); + } + if(partpriorities[ESM::PRT_RFoot] < 1){ + const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); + if(isBeast) + footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); + if(footPart) + addOrReplaceIndividualPart(ESM::PRT_RFoot, -1,1,"meshes\\" + footPart->model); + } + if(partpriorities[ESM::PRT_LFoot] < 1){ + const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); + if(isBeast) + footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); + if(footPart) + addOrReplaceIndividualPart(ESM::PRT_LFoot, -1,1,"meshes\\" + footPart->model); + } + if(partpriorities[ESM::PRT_RAnkle] < 1){ + const ESM::BodyPart *anklePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle"); + if(anklePart) + addOrReplaceIndividualPart(ESM::PRT_RAnkle, -1,1,"meshes\\" + anklePart->model); + } + if(partpriorities[ESM::PRT_LAnkle] < 1){ + const ESM::BodyPart *anklePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle"); + if(anklePart) + addOrReplaceIndividualPart(ESM::PRT_LAnkle, -1,1,"meshes\\" + anklePart->model); + } + if(partpriorities[ESM::PRT_RKnee] < 1){ + const ESM::BodyPart *kneePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee"); + if(kneePart) + addOrReplaceIndividualPart(ESM::PRT_RKnee, -1,1,"meshes\\" + kneePart->model); + } + if(partpriorities[ESM::PRT_LKnee] < 1){ + const ESM::BodyPart *kneePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee"); + if(kneePart) + addOrReplaceIndividualPart(ESM::PRT_LKnee, -1,1,"meshes\\" + kneePart->model); + } + if(partpriorities[ESM::PRT_RLeg] < 1){ + const ESM::BodyPart *legPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); + if(legPart) + addOrReplaceIndividualPart(ESM::PRT_RLeg, -1,1,"meshes\\" + legPart->model); + } + if(partpriorities[ESM::PRT_LLeg] < 1){ + const ESM::BodyPart *legPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); + if(legPart) + addOrReplaceIndividualPart(ESM::PRT_LLeg, -1,1,"meshes\\" + legPart->model); + } + if(partpriorities[ESM::PRT_Tail] < 1){ + const ESM::BodyPart *tailPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail"); + if(tailPart) + addOrReplaceIndividualPart(ESM::PRT_Tail, -1,1,"meshes\\" + tailPart->model); + } + + + From 45a5877b235e6e41841e83554ada94b0186b9000 Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 12:05:46 +0200 Subject: [PATCH 152/185] implement getPCRank. Does not work yet. --- apps/openmw/mwscript/docs/vmformat.txt | 6 ++- apps/openmw/mwscript/statsextensions.cpp | 53 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index fda8d1954..c38ff611c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -26,8 +26,10 @@ op 0x20009: LoopAnim, explicit reference op 0x2000a: Choice op 0x2000b: PCRaiseRank op 0x2000c: PCLowerRank -op x20000d: PCJoinFaction -opcodes 0x2000e-0x3ffff unused +op 0x2000d: PCJoinFaction +op 0x2000e: PCGetRank implicit +op 0x2000f: PCGetRank explicit +opcodes 0x20010-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 9d3009870..727b2d0e1 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -435,6 +435,54 @@ namespace MWScript } }; + template + class OpGetPCRank : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + runtime.pop(); + + std::string factionID = ""; + if(arg0 >0) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.empty()) + { + //throw exception? + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.begin()->first; + } + } + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + if(factionID!="") + { + if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) != MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + { + runtime.push(MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID]); + } + else + { + runtime.push(-1); + } + } + else + { + runtime.push(-1); + } + } + }; + template class OpModDisposition : public Interpreter::Opcode0 { @@ -492,6 +540,8 @@ namespace MWScript const int opcodePCRaiseRank = 0x2000b; const int opcodePCLowerRank = 0x2000c; const int opcodePCJoinFaction = 0x2000d; + const int opcodeGetPCRank = 0x2000e; + const int opcodeGetPCRankExplicit = 0x2000f; const int opcodeModDisposition = 0x200014d; const int opcodeModDispositionExplicit = 0x200014e; @@ -576,6 +626,7 @@ namespace MWScript extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); extensions.registerInstruction("moddisposition","l",opcodeModDisposition, opcodeModDispositionExplicit); + extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -645,6 +696,8 @@ namespace MWScript interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); + interpreter.installSegment3(opcodeGetPCRank,new OpGetPCRank); + interpreter.installSegment3(opcodeGetPCRankExplicit,new OpGetPCRank); } } } From f68248e0d0800d37a18afde61fa2380ec79dccd4 Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 14:20:08 +0200 Subject: [PATCH 153/185] corrected a bug in getPCRank --- apps/openmw/mwscript/statsextensions.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 727b2d0e1..239f8d768 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -443,7 +443,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { MWWorld::Ptr ptr = R()(runtime); - runtime.pop(); std::string factionID = ""; if(arg0 >0) From c24a85848f0d162b76c320465e524883e8124d07 Mon Sep 17 00:00:00 2001 From: gugus Date: Sun, 15 Apr 2012 15:56:36 +0200 Subject: [PATCH 154/185] forceGreeting script instruction --- apps/openmw/mwscript/dialogueextensions.cpp | 17 +++++++++++++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 0cca028e2..178485f78 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,7 @@ #include "../mwdialogue/dialoguemanager.hpp" #include "interpretercontext.hpp" +#include "ref.hpp" namespace MWScript { @@ -115,12 +116,26 @@ namespace MWScript } }; + template + class OpForceGreeting : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + context.getEnvironment().mDialogueManager->startDialogue (ptr); + } + }; const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; const int opcodeAddTopic = 0x200013a; const int opcodeChoice = 0x2000a; + const int opcodeForceGreeting = 0x200014f; void registerExtensions (Compiler::Extensions& extensions) { @@ -129,6 +144,7 @@ namespace MWScript extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); + extensions.registerInstruction("forcegreeting","",-1,opcodeForceGreeting); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -138,6 +154,7 @@ namespace MWScript interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic); interpreter.installSegment3 (opcodeChoice,new OpChoice); + interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index c38ff611c..9155746ed 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -142,4 +142,5 @@ op 0x200014b: GetSpell op 0x200014c: GetSpell, explicit reference op 0x200014d: ModDisposition op 0x200014e: ModDisposition, explicit reference -opcodes 0x200014f-0x3ffffff unused +op 0x200014f: ForceGreeting +opcodes 0x200015-0x3ffffff unused From b5d12d0723731a39ef6ce1bf61c669bf47957bc1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 15 Apr 2012 17:08:22 +0200 Subject: [PATCH 155/185] fixed ForceGreeting --- apps/openmw/mwscript/dialogueextensions.cpp | 8 ++++++-- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 178485f78..fec539d3e 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -136,6 +136,7 @@ namespace MWScript const int opcodeAddTopic = 0x200013a; const int opcodeChoice = 0x2000a; const int opcodeForceGreeting = 0x200014f; + const int opcodeForceGreetingExplicit = 0x2000150; void registerExtensions (Compiler::Extensions& extensions) { @@ -144,7 +145,9 @@ namespace MWScript extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); - extensions.registerInstruction("forcegreeting","",-1,opcodeForceGreeting); + extensions.registerInstruction("forcegreeting","",opcodeForceGreeting); + extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, + opcodeForceGreetingExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -154,7 +157,8 @@ namespace MWScript interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic); interpreter.installSegment3 (opcodeChoice,new OpChoice); - interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); + interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); + interpreter.installSegment5 (opcodeForceGreetingExplicit, new OpForceGreeting); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 9155746ed..58960aac4 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -143,4 +143,5 @@ op 0x200014c: GetSpell, explicit reference op 0x200014d: ModDisposition op 0x200014e: ModDisposition, explicit reference op 0x200014f: ForceGreeting -opcodes 0x200015-0x3ffffff unused +op 0x2000150: ForceGreeting, explicit reference +opcodes 0x2000151-0x3ffffff unused From 1b5d327f7e7ec8d94c7c25baee11cd4252db74be Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 15 Apr 2012 18:56:46 +0200 Subject: [PATCH 156/185] Fixed OS X build with static MyGUI --- cmake/FindFreetype.cmake | 69 ++++++++++++++++++++++++++++++++ cmake/FindMyGUI.cmake | 86 ++++++++++++++++++++++++---------------- 2 files changed, 121 insertions(+), 34 deletions(-) create mode 100644 cmake/FindFreetype.cmake diff --git a/cmake/FindFreetype.cmake b/cmake/FindFreetype.cmake new file mode 100644 index 000000000..fc36d548e --- /dev/null +++ b/cmake/FindFreetype.cmake @@ -0,0 +1,69 @@ +#------------------------------------------------------------------- +# This file is part of the CMake build system for OGRE +# (Object-oriented Graphics Rendering Engine) +# For the latest info, see http://www.ogre3d.org/ +# +# The contents of this file are placed in the public domain. Feel +# free to make use of it in any way you like. +#------------------------------------------------------------------- + +# - Try to find FreeType +# Once done, this will define +# +# FREETYPE_FOUND - system has FreeType +# FREETYPE_INCLUDE_DIRS - the FreeType include directories +# FREETYPE_LIBRARIES - link these to use FreeType + +include(FindPkgMacros) +findpkg_begin(FREETYPE) + +# Get path, convert backslashes as ${ENV_${var}} +getenv_path(FREETYPE_HOME) + +# construct search paths +set(FREETYPE_PREFIX_PATH ${FREETYPE_HOME} ${ENV_FREETYPE_HOME}) +create_search_paths(FREETYPE) +# redo search if prefix path changed +clear_if_changed(FREETYPE_PREFIX_PATH + FREETYPE_LIBRARY_FWK + FREETYPE_LIBRARY_REL + FREETYPE_LIBRARY_DBG + FREETYPE_INCLUDE_DIR +) + +set(FREETYPE_LIBRARY_NAMES freetype2311 freetype239 freetype238 freetype235 freetype219 freetype) +get_debug_names(FREETYPE_LIBRARY_NAMES) + +use_pkgconfig(FREETYPE_PKGC freetype2) + +# prefer static library over framework +set(CMAKE_FIND_FRAMEWORK "LAST") + +message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") +findpkg_framework(FREETYPE) +message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") + +find_path(FREETYPE_INCLUDE_DIR NAMES freetype/freetype.h HINTS ${FREETYPE_INC_SEARCH_PATH} ${FREETYPE_PKGC_INCLUDE_DIRS} PATH_SUFFIXES freetype2) +find_path(FREETYPE_FT2BUILD_INCLUDE_DIR NAMES ft2build.h HINTS ${FREETYPE_INC_SEARCH_PATH} ${FREETYPE_PKGC_INCLUDE_DIRS}) + +if (SYMBIAN) +set(ORIGINAL_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) +set(CMAKE_PREFIX_PATH ${CMAKE_SYSYEM_OUT_DIR}) +message(STATUS "Lib will be searched in Symbian out dir: ${CMAKE_SYSYEM_OUT_DIR}") +endif (SYMBIAN) +find_library(FREETYPE_LIBRARY_REL NAMES ${FREETYPE_LIBRARY_NAMES} HINTS ${FREETYPE_LIB_SEARCH_PATH} ${FREETYPE_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) +find_library(FREETYPE_LIBRARY_DBG NAMES ${FREETYPE_LIBRARY_NAMES_DBG} HINTS ${FREETYPE_LIB_SEARCH_PATH} ${FREETYPE_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) +if (SYMBIAN) +set(CMAKE_PREFIX_PATH ${ORIGINAL_CMAKE_PREFIX_PATH}) +endif (SYMBIAN) + +make_library_set(FREETYPE_LIBRARY) + +findpkg_finish(FREETYPE) +mark_as_advanced(FREETYPE_FT2BUILD_INCLUDE_DIR) +if (NOT FREETYPE_FT2BUILD_INCLUDE_DIR STREQUAL FREETYPE_INCLUDE_DIR) + set(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${FREETYPE_FT2BUILD_INCLUDE_DIR}) +endif () + +# Reset framework finding +set(CMAKE_FIND_FRAMEWORK "FIRST") diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 6731d584c..dbcf8f11c 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -82,37 +82,49 @@ findpkg_finish ( "MYGUI" ) ELSE (WIN32) #Unix CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) FIND_PACKAGE(PkgConfig) - IF(MYGUI_STATIC) - PKG_SEARCH_MODULE(MYGUI MYGUIStatic MyGUIStatic) - IF (MYGUI_INCLUDE_DIRS) - SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) - SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) - SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") - ELSE (MYGUI_INCLUDE_DIRS) - FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") - SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) - STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") - STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") - ENDIF (MYGUI_INCLUDE_DIRS) - ELSE(MYGUI_STATIC) - PKG_SEARCH_MODULE(MYGUI MYGUI MyGUI) - IF (MYGUI_INCLUDE_DIRS) - SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) - SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) - SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") - ELSE (MYGUI_INCLUDE_DIRS) - FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) - FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) - SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") - SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) - STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") - STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") - ENDIF (MYGUI_INCLUDE_DIRS) - ENDIF(MYGUI_STATIC) + IF(MYGUI_STATIC) + # don't use pkgconfig on OS X, find freetype & append it's libs to resulting MYGUI_LIBRARIES + IF (NOT APPLE) + PKG_SEARCH_MODULE(MYGUI MYGUIStatic MyGUIStatic) + IF (MYGUI_INCLUDE_DIRS) + SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) + SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) + SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + ELSE (MYGUI_INCLUDE_DIRS) + FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) + FIND_LIBRARY(MYGUI_LIBRARIES myguistatic PATHS /usr/lib /usr/local/lib) + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) + STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") + STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") + ENDIF (MYGUI_INCLUDE_DIRS) + ELSE (NOT APPLE) + SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${MYGUI_DEPENDENCIES_DIR} ${OGRE_DEPENDENCIES_DIR}) + FIND_PACKAGE(freetype) + FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) + FIND_LIBRARY(MYGUI_LIBRARIES MyGUIEngineStatic PATHS /usr/lib /usr/local/lib) + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) + STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") + STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") + ENDIF (NOT APPLE) + ELSE(MYGUI_STATIC) + PKG_SEARCH_MODULE(MYGUI MYGUI MyGUI) + IF (MYGUI_INCLUDE_DIRS) + SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) + SET(MYGUI_LIB_DIR ${MYGUI_LIBDIR}) + SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + ELSE (MYGUI_INCLUDE_DIRS) + FIND_PATH(MYGUI_INCLUDE_DIRS MyGUI.h PATHS /usr/local/include /usr/include PATH_SUFFIXES MyGUI MYGUI) + FIND_LIBRARY(MYGUI_LIBRARIES mygui PATHS /usr/lib /usr/local/lib) + SET(MYGUI_PLATFORM_LIBRARIES "MyGUI.OgrePlatform") + SET(MYGUI_LIB_DIR ${MYGUI_LIBRARIES}) + STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") + STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") + ENDIF (MYGUI_INCLUDE_DIRS) + ENDIF(MYGUI_STATIC) ENDIF (WIN32) #Do some preparation @@ -120,17 +132,23 @@ SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS) SEPARATE_ARGUMENTS(MYGUI_LIBRARIES) SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES) +SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} ${FREETYPE_LIBRARIES}) + SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS} CACHE PATH "") SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "") SET(MYGUI_LIB_DIR ${MYGUI_LIB_DIR} CACHE PATH "") -IF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES) +IF (NOT APPLE OR NOT MYGUI_STATIC) # we need freetype libs only on OS X for static build, for other cases just make it TRUE + SET(FREETYPE_LIBRARIES TRUE) +ENDIF (NOT APPLE OR NOT MYGUI_STATIC) + +IF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES AND FREETYPE_LIBRARIES) SET(MYGUI_FOUND TRUE) -ENDIF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES) +ENDIF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES AND FREETYPE_LIBRARIES) IF (MYGUI_FOUND) -MARK_AS_ADVANCED(MYGUI_LIB_DIR) + MARK_AS_ADVANCED(MYGUI_LIB_DIR) IF (NOT MYGUI_FIND_QUIETLY) MESSAGE(STATUS " libraries : ${MYGUI_LIBRARIES} from ${MYGUI_LIB_DIR}") MESSAGE(STATUS " includes : ${MYGUI_INCLUDE_DIRS}") From bc8bb9c57ead538e4568f629b68b40863804c0be Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 15 Apr 2012 14:22:55 -0400 Subject: [PATCH 157/185] Reserve; skirts --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d0019154e..5755418e2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -303,8 +303,8 @@ namespace MWRender{ for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++) { - if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){ - Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter); + if(skel->hasBone(*boneSequenceIter)){ + Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter); // Computes C = B + AxC*scale transmult = transmult + rotmult * bonePtr->getPosition(); rotmult = rotmult * bonePtr->getOrientation(); From 65c9cf565c70c4c49cbe484df96811c6e214fb28 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 15 Apr 2012 15:16:48 -0400 Subject: [PATCH 158/185] Skirt and robe part blanking --- apps/openmw/mwrender/npcanimation.cpp | 78 +++++++++++++++++++-------- apps/openmw/mwrender/npcanimation.hpp | 7 ++- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index bc134581d..2f8763549 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -13,12 +13,12 @@ NpcAnimation::~NpcAnimation(){ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), - robe(inv.getSlot(MWWorld::InventoryStore::Slot_Robe)), helmet(inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)), shirt(inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)), - cuirass(inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)), greaves(inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)), - leftpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)), rightpauldron(inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)), - boots(inv.getSlot(MWWorld::InventoryStore::Slot_Boots)), - leftglove(inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)), rightglove(inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)), - pants(inv.getSlot(MWWorld::InventoryStore::Slot_Pants)), + robe(inv.end()), helmet(inv.end()), shirt(inv.end()), + cuirass(inv.end()), greaves(inv.end()), + leftpauldron(inv.end()), rightpauldron(inv.end()), + boots(inv.end()), + leftglove(inv.end()), rightglove(inv.end()), skirtiter(inv.end()), + pants(inv.end()), lclavicle(0), rclavicle(0), rupperArm(0), @@ -74,8 +74,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O // vector = Ogre::Vector3(1,1,-1); - hairID = ref->base->hair; - headID = ref->base->head; + std::string hairID = ref->base->hair; + std::string headID = ref->base->head; + headModel = "meshes\\" + + mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; + + hairModel = "meshes\\" + + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; npcName = ref->base->name; //ESMStore::Races r = const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); @@ -159,11 +164,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O } void NpcAnimation::updateParts(){ - std::string headModel = "meshes\\" + - mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; - - std::string hairModel = "meshes\\" + - mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; + bool apparelChanged = false; @@ -173,8 +174,12 @@ void NpcAnimation::updateParts(){ removePartGroup(MWWorld::InventoryStore::Slot_Robe); robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); apparelChanged = true; - - + } + if(skirtiter != inv.getSlot(MWWorld::InventoryStore::Slot_Skirt)){ + //A robe was added or removed + removePartGroup(MWWorld::InventoryStore::Slot_Skirt); + skirtiter = inv.getSlot(MWWorld::InventoryStore::Slot_Skirt); + apparelChanged = true; } if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ apparelChanged = true; @@ -237,7 +242,6 @@ void NpcAnimation::updateParts(){ } if(apparelChanged){ - std::cout << "Modifying stuff\n"; if(robe != inv.end()) { MWWorld::Ptr ptr = *robe; @@ -245,6 +249,29 @@ void NpcAnimation::updateParts(){ const ESM::Clothing *clothes = (ptr.get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + } + if(skirtiter != inv.end()) + { + MWWorld::Ptr ptr = *skirtiter; + + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } if(helmet != inv.end()){ @@ -489,7 +516,6 @@ std::pair*> NpcAnimation::insert std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix)); if(shape){ - handleShapes(shape, part, base->getSkeleton()); } std::pair*> pair = std::make_pair(part, shape); @@ -541,8 +567,9 @@ void NpcAnimation::runAnimation(float timepassed){ handleShapes(chest.second, chest.first, base->getSkeleton()); if(tail.first) handleShapes(tail.second, tail.first, base->getSkeleton()); - if(skirt.first) + if(skirt.first){ handleShapes(skirt.second, skirt.first, base->getSkeleton()); + } if(lhand.first) handleShapes(lhand.second, lhand.first, base->getSkeleton()); if(rhand.first) @@ -677,6 +704,14 @@ void NpcAnimation::removeIndividualPart(int type){ + } + + void NpcAnimation::reserveIndividualPart(int type, int group, int priority){ + if(priority > partpriorities[type]){ + removeIndividualPart(type); + partpriorities[type] = priority; + partslots[type] = group; + } } void NpcAnimation::removePartGroup(int group){ @@ -705,7 +740,7 @@ void NpcAnimation::removeIndividualPart(int type){ chest = insertFreePart(mesh, ":\""); break; case ESM::PRT_Groin: //4 - neck = insertBoundedPart(mesh, "Groin"); + groin = insertBoundedPart(mesh, "Groin"); break; case ESM::PRT_Skirt: //5 skirt = insertFreePart(mesh, ":|"); @@ -791,16 +826,15 @@ void NpcAnimation::removeIndividualPart(int type){ { ESM::PartReference part = parts[i]; - const ESM::BodyPart *bodypart = 0; - if(isFemale) bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.female); if(!bodypart) bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); + else + reserveIndividualPart(part.part, group, priority); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 255989d28..c7c22ad55 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -63,8 +63,8 @@ private: Ogre::SceneNode* insert; bool isBeast; bool isFemale; - std::string headID; - std::string hairID; + std::string headModel; + std::string hairModel; std::string npcName; std::string bodyRaceID; float timeToChange; @@ -79,6 +79,7 @@ private: MWWorld::ContainerStoreIterator pants; MWWorld::ContainerStoreIterator leftglove; MWWorld::ContainerStoreIterator rightglove; + MWWorld::ContainerStoreIterator skirtiter; public: NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); @@ -88,10 +89,12 @@ private: virtual void runAnimation(float timepassed); void updateParts(); void removeIndividualPart(int type); + void reserveIndividualPart(int type, int group, int priority); bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); + }; } From 677a907528f9e5fbcecabc2a4489efb119e950c5 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 15 Apr 2012 21:37:33 +0200 Subject: [PATCH 159/185] fixed comment --- cmake/FindMyGUI.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index dbcf8f11c..c79ee5998 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -139,7 +139,7 @@ SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "") SET(MYGUI_LIB_DIR ${MYGUI_LIB_DIR} CACHE PATH "") -IF (NOT APPLE OR NOT MYGUI_STATIC) # we need freetype libs only on OS X for static build, for other cases just make it TRUE +IF (NOT APPLE OR NOT MYGUI_STATIC) # we need explicit freetype libs only on OS X for static build, for other cases just make it TRUE SET(FREETYPE_LIBRARIES TRUE) ENDIF (NOT APPLE OR NOT MYGUI_STATIC) From 268b7cd6fc3a5f9e6281ba6627be735a461a8665 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 22:05:33 +0200 Subject: [PATCH 160/185] replaced typename checks --- apps/openmw/mwrender/npcanimation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9cc3c26f6..0f25a1ff4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -308,12 +308,12 @@ void NpcAnimation::updateParts(){ } if(!isBeast && boots != inv.end()){ - if(boots->getTypeName() == "struct ESM::Clothing"){ + if(boots->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (boots->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); } - else + else if(boots->getTypeName() == typeid(ESM::Armor).name()) { const ESM::Armor *armor = (boots->get())->base; std::vector parts = armor->parts.parts; @@ -323,7 +323,7 @@ void NpcAnimation::updateParts(){ } if(leftglove != inv.end()){ - if(leftglove->getTypeName() == "struct ESM::Clothing"){ + if(leftglove->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (leftglove->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); @@ -338,7 +338,7 @@ void NpcAnimation::updateParts(){ } if(rightglove != inv.end()){ - if(rightglove->getTypeName() == "struct ESM::Clothing"){ + if(rightglove->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (rightglove->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); From 10398723d877b6ce1b6469fc470dbd96b9a1b236 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 22:44:38 +0200 Subject: [PATCH 161/185] use different image pixel format --- libs/openengine/ogre/imagerotate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index 1147559d6..11fd5eea6 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -54,7 +54,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest TEX_TYPE_2D, width, height, 0, - PF_A8R8G8B8, + PF_FLOAT16_RGBA, TU_RENDERTARGET); RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); @@ -63,7 +63,6 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0,0,0,0)); - vp->setClearEveryFrame(true, FBT_DEPTH); rtt->update(); From b76fd249c7272350015fff07a9936cfa94448cb2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 15 Apr 2012 23:18:34 +0200 Subject: [PATCH 162/185] updated changelog; bumped version number --- CMakeLists.txt | 6 +++--- readme.txt | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 713cfa3e2..f1325c784 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 13) +set (OPENMW_VERSION_MINOR 14) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -122,7 +122,7 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h - + ) set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) @@ -361,7 +361,7 @@ if(WIN32) INSTALL(FILES ${files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES - "${OpenMW_SOURCE_DIR}/readme.txt" + "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") diff --git a/readme.txt b/readme.txt index e1c24ab52..52c4e11a2 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.13.0 +Version: 0.14.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -64,8 +64,6 @@ Allowed options: --start arg (=Beshara) set initial cell --master arg master file(s) --plugin arg plugin file(s) - --fps [=arg(=1)] (=0) fps counter detail (0 = off, 1 = fps counter - , 2 = full detail) --anim-verbose [=arg(=1)] (=0) output animation indices files --debug [=arg(=1)] (=0) debug mode --nosound [=arg(=1)] (=0) disable all sounds @@ -90,6 +88,7 @@ Allowed options: win1252 - Western European (Latin) alphabet, used by default --report-focus [=arg(=1)] (=0) write name of focussed object to cout + --fallback arg fallback values CREDITS @@ -134,6 +133,36 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil CHANGELOG +0.14.0 + +Bug #1: Meshes rendered with wrong orientation +Bug #6/Task #220: Picking up small objects doesn't always work +Bug #127: tcg doesn't work +Bug #178: Compablity problems with Ogre 1.8.0 RC 1 +Bug #211: Wireframe mode (toggleWireframe command) should not apply to Console & other UI +Bug #227: Terrain crashes when moving away from predefined cells +Bug #229: On OS X Launcher cannot launch game if path to binary contains spaces +Bug #235: TGA texture loading problem +Bug #246: wireframe mode does not work in water +Feature #8/#232: Water Rendering +Feature #13: Terrain Rendering +Feature #37: Render Path Grid +Feature #66: Factions +Feature #77: Local Map +Feature #78: Compass/Mini-Map +Feature #97: Render Clothing/Armour +Feature #121: Window Pinning +Feature #205: Auto equip +Feature #217: Contiainer should track changes to its content +Feature #221: NPC Dialogue Window Enhancements +Feature #233: Game settings manager +Feature #240: Spell List and selected spell (no GUI yet) +Feature #243: Draw State +Task #113: Morrowind.ini Importer +Task #215: Refactor the sound code +Task #216: Update MyGUI + + 0.13.0 Bug #145: Fixed sound problems after cell change From 0c9c2537784f8209c4cfc81ee169e498571792c3 Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Sun, 15 Apr 2012 22:49:17 -0400 Subject: [PATCH 163/185] Fix for some types of boots --- apps/openmw/mwrender/npcanimation.cpp | 77 ++++++++++++++++++--------- apps/openmw/mwrender/npcanimation.hpp | 5 +- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2f8763549..4105606a9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -45,8 +45,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O zero = std::make_pair(blank, blankshape); chest = std::make_pair(blank, blankshape); tail = std::make_pair(blank, blankshape); - lBeastFoot = std::make_pair(blank, blankshape); - rBeastFoot = std::make_pair(blank, blankshape); + lFreeFoot = std::make_pair(blank, blankshape); + rFreeFoot = std::make_pair(blank, blankshape); rhand = std::make_pair(blank, blankshape); lhand = std::make_pair(blank, blankshape); skirt = std::make_pair(blank, blankshape); @@ -82,6 +82,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O hairModel = "meshes\\" + mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; npcName = ref->base->name; + //ESMStore::Races r = const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); @@ -242,6 +243,7 @@ void NpcAnimation::updateParts(){ } if(apparelChanged){ + if(robe != inv.end()) { MWWorld::Ptr ptr = *robe; @@ -308,12 +310,12 @@ void NpcAnimation::updateParts(){ } if(!isBeast && boots != inv.end()){ - if(boots->getTypeName() == "struct ESM::Clothing"){ + if(boots->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (boots->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); } - else + else if(boots->getTypeName() == typeid(ESM::Armor).name()) { const ESM::Armor *armor = (boots->get())->base; std::vector parts = armor->parts.parts; @@ -323,7 +325,7 @@ void NpcAnimation::updateParts(){ } if(leftglove != inv.end()){ - if(leftglove->getTypeName() == "struct ESM::Clothing"){ + if(leftglove->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (leftglove->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); @@ -338,7 +340,7 @@ void NpcAnimation::updateParts(){ } if(rightglove != inv.end()){ - if(rightglove->getTypeName() == "struct ESM::Clothing"){ + if(rightglove->getTypeName() == typeid(ESM::Clothing).name()){ const ESM::Clothing *clothes = (rightglove->get())->base; std::vector parts = clothes->parts.parts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); @@ -501,6 +503,33 @@ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::stri base->attachObjectToBone(bonename, part); return part; +} +void NpcAnimation::insertFootPart(int type, const std::string &mesh){ + std::string meshAndSuffix = mesh; + if(type == ESM::PRT_LFoot) + meshAndSuffix += "*|"; + NIFLoader::load(meshAndSuffix); + Ogre::Entity* part = mRend.getScene()->createEntity(meshAndSuffix); + std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(meshAndSuffix)); + if(shape == 0){ + if(type == ESM::PRT_LFoot){ + base->attachObjectToBone("Left Foot", part); + lfoot = part; + } + else if (type == ESM::PRT_RFoot){ + base->attachObjectToBone("Right Foot", part); + rfoot = part; + } + } + else{ + if(type == ESM::PRT_LFoot) + lFreeFoot = insertFreePart(mesh, "::"); + else if (type == ESM::PRT_RFoot) + rFreeFoot = insertFreePart(mesh, ":<"); + } + + + } std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix){ @@ -559,10 +588,10 @@ void NpcAnimation::runAnimation(float timepassed){ vecRotPos.clear(); - if(lBeastFoot.first) - handleShapes(lBeastFoot.second, lBeastFoot.first, base->getSkeleton()); - if(rBeastFoot.first) - handleShapes(rBeastFoot.second, rBeastFoot.first, base->getSkeleton()); + if(lFreeFoot.first) + handleShapes(lFreeFoot.second, lFreeFoot.first, base->getSkeleton()); + if(rFreeFoot.first) + handleShapes(rFreeFoot.second, rFreeFoot.first, base->getSkeleton()); if(chest.first) handleShapes(chest.second, chest.first, base->getSkeleton()); if(tail.first) @@ -646,9 +675,9 @@ void NpcAnimation::removeIndividualPart(int type){ base->detachObjectFromBone(rfoot); rfoot = 0; } - else if(rBeastFoot.first){ - insert->detachObject(rBeastFoot.first); - rBeastFoot = zero; + else if(rFreeFoot.first){ + insert->detachObject(rFreeFoot.first); + rFreeFoot = zero; } } else if(type == ESM::PRT_LFoot){ //16 @@ -656,9 +685,9 @@ void NpcAnimation::removeIndividualPart(int type){ base->detachObjectFromBone(lfoot); lfoot = 0; } - else if(lBeastFoot.first){ - insert->detachObject(lBeastFoot.first); - lBeastFoot = zero; + else if(lFreeFoot.first){ + insert->detachObject(lFreeFoot.first); + lFreeFoot = zero; } } else if(type == ESM::PRT_RAnkle && rAnkle){ //17 @@ -772,16 +801,10 @@ void NpcAnimation::removeIndividualPart(int type){ lupperArm = insertBoundedPart(mesh + "*|", "Left Upper Arm"); break; case ESM::PRT_RFoot: //15 - if(isBeast) - rBeastFoot = insertFreePart(mesh, ":<"); - else - rfoot = insertBoundedPart(mesh, "Right Foot"); + insertFootPart(type, mesh); break; case ESM::PRT_LFoot: //16 - if(isBeast) - lBeastFoot = insertFreePart(mesh, "::"); - else - lfoot = insertBoundedPart(mesh + "*|", "Left Foot"); + insertFootPart(type, mesh); break; case ESM::PRT_RAnkle: //17 @@ -827,13 +850,15 @@ void NpcAnimation::removeIndividualPart(int type){ ESM::PartReference part = parts[i]; const ESM::BodyPart *bodypart = 0; + if(isFemale) bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.female); if(!bodypart) bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); - if(bodypart) + if(bodypart){ addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); - else + } + else reserveIndividualPart(part.part, group, priority); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index c7c22ad55..352b54bec 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -29,8 +29,8 @@ private: std::pair*> lhand; std::pair*> rhand; std::pair*> tail; - std::pair*> lBeastFoot; - std::pair*> rBeastFoot; + std::pair*> lFreeFoot; + std::pair*> rFreeFoot; int partslots[27]; //Each part slot is taken by clothing, armor, or is empty int partpriorities[27]; @@ -86,6 +86,7 @@ private: virtual ~NpcAnimation(); Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); + void insertFootPart(int type, const std::string &mesh); virtual void runAnimation(float timepassed); void updateParts(); void removeIndividualPart(int type); From 582d7ab2133585fbe42dbcb2b49ffa6eabe72eb7 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 16 Apr 2012 15:27:57 +0200 Subject: [PATCH 164/185] building & packaging improvements for OS X --- CMakeLists.txt | 107 +++++++++++++++++++++++++----------------- files/plugins.cfg.mac | 10 ++-- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f1325c784..692aa6e51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,16 +210,16 @@ include_directories("." link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) -if(APPLE) +if (APPLE) # List used Ogre plugins - SET(USED_OGRE_PLUGINS "RenderSystem_GL" - "Plugin_OctreeSceneManager" - "Plugin_CgProgramManager" - "Plugin_ParticleFX") -endif(APPLE) + SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} + ${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL} + ${OGRE_Plugin_CgProgramManager_LIBRARY_REL} + ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) +endif (APPLE) -add_subdirectory( files/) -add_subdirectory( files/mygui ) +add_subdirectory(files/) +add_subdirectory(files/mygui) # Specify build paths @@ -256,34 +256,50 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() if (APPLE) - configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac - "${OpenMW_BINARY_DIR}/plugins.cfg") - - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist - "${APP_BUNDLE_DIR}/Contents/Info.plist") - - configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns - "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) - # prepare plugins if (${CMAKE_BUILD_TYPE} MATCHES "Release") - set(OPENMW_RELEASE_BUILD 1) + set(OPENMW_RELEASE_BUILD TRUE) endif() if (${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo") - set(OPENMW_RELEASE_BUILD 1) + set(OPENMW_RELEASE_BUILD TRUE) endif() - if (${OPENMW_RELEASE_BUILD}) + if (${OGRE_PLUGIN_DIR_REL}}) + set(OGRE_PLUGINS_REL_FOUND TRUE) + endif () + + if (${OGRE_PLUGIN_DIR_DBG}) + set(OGRE_PLUGINS_DBG_FOUND TRUE) + endif () + + if (${OPENMW_RELEASE_BUILD} AND ${OGRE_PLUGINS_REL_FOUND}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - else() + else () + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) + endif () + + if (NOT ${OPENMW_RELEASE_BUILD} AND ${OGRE_PLUGINS_DBG_FOUND}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) + else() + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) endif() - foreach(plugin ${USED_OGRE_PLUGINS}) - configure_file("${OGRE_PLUGIN_DIR}/${plugin}.dylib" - "${APP_BUNDLE_DIR}/Contents/Plugins/${plugin}.dylib" - COPYONLY) - endforeach() + set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") + + configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac + "${OpenMW_BINARY_DIR}/plugins.cfg") + + set(OGRE_PLUGIN_DIR_2 ${OGRE_PLUGIN_DIR}) + set(OGRE_PLUGIN_DIR "") + configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac + "${OpenMW_BINARY_DIR}/plugins.cfg.install") + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_2}) + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + "${APP_BUNDLE_DIR}/Contents/Info.plist") + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns + "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) endif (APPLE) @@ -521,10 +537,12 @@ if (APPLE) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - - install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg.install" RENAME "plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) @@ -533,22 +551,25 @@ if (APPLE) set(APPS "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") set(PLUGINS "") + set(ABSOLUTE_PLUGINS "") - # Scan Plugins dir for *.dylibs - set(PLUGIN_SEARCH_ROOT "${APP_BUNDLE_DIR}/Contents/Plugins") - file(GLOB_RECURSE ALL_PLUGINS "${PLUGIN_SEARCH_ROOT}/*.dylib") + foreach (PLUGIN ${USED_OGRE_PLUGINS}) + get_filename_component(PLUGIN_ABS ${PLUGIN} REALPATH) + set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) + endforeach () set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins") - foreach(PLUGIN ${ALL_PLUGINS}) - string(REPLACE "${PLUGIN_SEARCH_ROOT}/" "" PLUGIN_RELATIVE "${PLUGIN}") + install(FILES ${ABSOLUTE_PLUGINS} DESTINATION "${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins" COMPONENT Runtime) + foreach (PLUGIN ${ABSOLUTE_PLUGINS}) + get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME) set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}") - endforeach() + endforeach () #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail set(DIRS "") # Overriding item resolving during installation, it needed if - # some library already has be "fixed up", i.e. its id name contains @executable_path, + # some library already has been "fixed up", i.e. its id name contains @executable_path, # but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK. # Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case. # @@ -568,15 +589,20 @@ if (APPLE) get_filename_component(fname \"\${item}\" NAME_WE) find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /Library/Frameworks) if (ri) - message(STATUS \"found \${ri} for \${item}\") string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item}) set(ri \"\${ri}\${item_part}\") set(\${resolved_item_var} \${ri} PARENT_SCOPE) set(\${resolved_var} 1 PARENT_SCOPE) - set(OPENMW_RESOLVED_ITEMS \${_OPENMW_RESOLVED_ITEMS} \${ri}) endif() else() # code path for standard (non-framework) libs (ogre & qt pugins) + get_filename_component(fname \"\${item}\" NAME_WE) + string(REGEX REPLACE \"^lib\" \"\" fname \${fname}) + find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /usr/lib /usr/local/lib) + if (ri) + set(\${resolved_item_var} \${ri} PARENT_SCOPE) + set(\${resolved_var} 1 PARENT_SCOPE) + endif () endif() endif() endfunction(gp_resolve_item_override) @@ -586,10 +612,5 @@ if (APPLE) include(BundleUtilities) fixup_bundle(\"${APPS}\" \"${PLUGINS}\" \"${DIRS}\") " COMPONENT Runtime) - -include(CPack) - -set(CMAKE_EXE_LINKER_FLAGS "-arch i386") -set(CMAKE_CXX_FLAGS "-arch i386") - + include(CPack) endif (APPLE) diff --git a/files/plugins.cfg.mac b/files/plugins.cfg.mac index 0c16bddaf..322070832 100644 --- a/files/plugins.cfg.mac +++ b/files/plugins.cfg.mac @@ -1,12 +1,12 @@ # Defines plugins to load # Define plugin folder -PluginFolder= +PluginFolder=${OGRE_PLUGIN_DIR} # Define plugins -Plugin=RenderSystem_GL.dylib -Plugin=Plugin_ParticleFX.dylib -Plugin=Plugin_OctreeSceneManager.dylib -Plugin=Plugin_CgProgramManager +Plugin=RenderSystem_GL.1.8.0 +Plugin=Plugin_ParticleFX.1.8.0 +Plugin=Plugin_OctreeSceneManager.1.8.0 +Plugin=Plugin_CgProgramManager.1.8.0 From 0c739825f25003047d77aec781924b2c0086f129 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Mon, 16 Apr 2012 15:57:50 +0200 Subject: [PATCH 165/185] another fix --- CMakeLists.txt | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 692aa6e51..40347898b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -256,14 +256,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() if (APPLE) - # prepare plugins - if (${CMAKE_BUILD_TYPE} MATCHES "Release") - set(OPENMW_RELEASE_BUILD TRUE) - endif() - if (${CMAKE_BUILD_TYPE} MATCHES "RelWithDebugInfo") - set(OPENMW_RELEASE_BUILD TRUE) - endif() - if (${OGRE_PLUGIN_DIR_REL}}) set(OGRE_PLUGINS_REL_FOUND TRUE) endif () @@ -272,17 +264,11 @@ if (APPLE) set(OGRE_PLUGINS_DBG_FOUND TRUE) endif () - if (${OPENMW_RELEASE_BUILD} AND ${OGRE_PLUGINS_REL_FOUND}) + if (${OGRE_PLUGINS_REL_FOUND}) set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) else () set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) endif () - - if (NOT ${OPENMW_RELEASE_BUILD} AND ${OGRE_PLUGINS_DBG_FOUND}) - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) - else() - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - endif() set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") @@ -587,7 +573,7 @@ if (APPLE) if (item MATCHES \"Frameworks\") # if it is a framework # get last segment of path get_filename_component(fname \"\${item}\" NAME_WE) - find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /Library/Frameworks) + find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} \${CMAKE_SYSTEM_FRAMEWORK_PATH}) if (ri) string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item}) set(ri \"\${ri}\${item_part}\") From 13b67faf2f38c3692db617c4d31d6f1c33ed3d74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 20:39:41 +0200 Subject: [PATCH 166/185] adding more safety checks --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- files/settings-default.cfg | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c1462807f..a35560848 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -54,9 +54,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2) + if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("shader", "Water", false); - if (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_4_0")) + if ( !(caps->isShaderProfileSupported("fp40") || caps->isShaderProfileSupported("ps_4_0")) + || !Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); // note that the order is important here diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 553a82e49..e4a0c020a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -86,6 +86,7 @@ num lights = 8 [Water] # Enable this to get fancy-looking water with reflections and refractions +# Only available if object shaders are on # All the settings below have no effect if this is false shader = true From 950378ff65d0a715c871abf080d5e6a9bbe6fa4e Mon Sep 17 00:00:00 2001 From: Jason Hooks Date: Mon, 16 Apr 2012 17:25:55 -0400 Subject: [PATCH 167/185] Khajiit male foot fix --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4105606a9..9292c857e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -439,14 +439,14 @@ void NpcAnimation::updateParts(){ } if(partpriorities[ESM::PRT_RFoot] < 1){ const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast) + if(isBeast && !footPart) footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); if(footPart) addOrReplaceIndividualPart(ESM::PRT_RFoot, -1,1,"meshes\\" + footPart->model); } if(partpriorities[ESM::PRT_LFoot] < 1){ const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast) + if(isBeast && !footPart) footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); if(footPart) addOrReplaceIndividualPart(ESM::PRT_LFoot, -1,1,"meshes\\" + footPart->model); From a11c4da16c3688d8a4760c7f866e8edc518614f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 14:22:03 +0200 Subject: [PATCH 168/185] vertex colour tweak --- apps/openmw/mwrender/shaderhelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp index 5354251f8..1d29be2b8 100644 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -256,9 +256,9 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s } outStream << - " float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" + " float3 lightingFinal = lightColour.xyz * diffuse.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" - " oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour.xyz, fogValue); \n" + " oColor.xyz = lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue); \n" " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << From 8231cab5996dc31f12efda82bfeecd156ec1f6f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 23:47:50 +0200 Subject: [PATCH 169/185] correct case for dialogue topics --- apps/openmw/mwdialogue/dialoguemanager.cpp | 16 ++--- apps/openmw/mwgui/dialogue.cpp | 10 ++++ components/esm_store/reclists.hpp | 69 ++++++++++++++++++++++ components/esm_store/store.cpp | 10 ++-- components/esm_store/store.hpp | 6 +- 5 files changed, 94 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 90f0c0231..3188136b3 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -549,10 +549,10 @@ namespace MWDialogue mCompilerContext.setExtensions (&extensions); mDialogueMap.clear(); actorKnownTopics.clear(); - ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; - for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { - mDialogueMap[it->first] = it->second; + mDialogueMap[toLower(it->first)] = it->second; } } @@ -602,8 +602,8 @@ namespace MWDialogue //greeting bool greetingFound = false; //ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; - ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; - for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { ESM::Dialogue ndialogue = it->second; if(ndialogue.type == ESM::Dialogue::Greeting) @@ -702,8 +702,8 @@ namespace MWDialogue mChoice = -1; actorKnownTopics.clear(); MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); - ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; - for(ESMS::RecListT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) + ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { ESM::Dialogue ndialogue = it->second; if(ndialogue.type == ESM::Dialogue::Topic) @@ -713,7 +713,7 @@ namespace MWDialogue { if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) { - actorKnownTopics.push_back(it->first); + actorKnownTopics.push_back(toLower(it->first)); //does the player know the topic? if(knownTopics.find(toLower(it->first)) != knownTopics.end()) { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index ac6681e27..fc7a36382 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -183,6 +183,16 @@ void DialogueWindow::addText(std::string text) void DialogueWindow::addTitle(std::string text) { + // This is called from the dialogue manager, so text is + // case-smashed - thus we have to retrieve the correct case + // of the text through the topic list. + for (size_t i=0; igetItemCount(); ++i) + { + std::string item = topicsList->getItemNameAt(i); + if (lower_string(item) == text) + text = item; + } + history->addDialogHeading(text); } diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index d7a4100aa..48bf050cd 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -90,6 +90,75 @@ namespace ESMS } }; + // Same as RecListT, but does not case-smash the IDs + // Note that lookups (search or find) are still case insensitive + template + struct RecListCaseT : RecList + { + virtual ~RecListCaseT() {} + + typedef std::map MapType; + + MapType list; + + // Load one object of this type + void load(ESMReader &esm, const std::string &id) + { + //std::string id2 = toLower (id); + + list[id].load(esm); + } + + // Find the given object ID, or return NULL if not found. + const X* search(const std::string &id) const + { + std::string id2 = toLower (id); + + for (typename MapType::const_iterator iter = list.begin(); + iter != list.end(); ++iter) + { + if (toLower(iter->first) == id2) + return &iter->second; + } + + return NULL; + } + + // non-const version + X* search(const std::string &id) + { + std::string id2 = toLower (id); + + for (typename MapType::iterator iter = list.begin(); + iter != list.end(); ++iter) + { + if (toLower(iter->first) == id2) + return &iter->second; + } + + return NULL; + } + + // Find the given object ID (throws an exception if not found) + const X* find(const std::string &id) const + { + const X *object = search (id); + + if (!object) + throw std::runtime_error ("object " + id + " not found"); + + return object; + } + + int getSize() { return list.size(); } + + virtual void listIdentifier (std::vector& identifier) const + { + for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) + identifier.push_back (iter->first); + } + }; + /// Modified version of RecListT for records, that need to store their own ID template struct RecListWithIDT : RecList diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index 2b5b977aa..c676601e5 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -71,15 +71,13 @@ void ESMStore::load(ESMReader &esm) if (n.val==ESM::REC_DIAL) { - RecListT& recList = static_cast& > (*it->second); + RecListCaseT& recList = static_cast& > (*it->second); - id = recList.toLower (id); + ESM::Dialogue* d = recList.search (id); - RecListT::MapType::iterator iter = recList.list.find (id); + assert (d != NULL); - assert (iter!=recList.list.end()); - - dialogue = &iter->second; + dialogue = d; } else dialogue = 0; diff --git a/components/esm_store/store.hpp b/components/esm_store/store.hpp index 857682089..507196a86 100644 --- a/components/esm_store/store.hpp +++ b/components/esm_store/store.hpp @@ -40,9 +40,9 @@ namespace ESMS RecListT clothes; RecListT contChange; RecListT containers; - RecListWithIDT creatures; + RecListWithIDT creatures; RecListT creaChange; - RecListT dialogs; + RecListCaseT dialogs; RecListT doors; RecListT enchants; RecListT factions; @@ -53,7 +53,7 @@ namespace ESMS RecListT lights; RecListT lockpicks; RecListT miscItems; - RecListWithIDT npcs; + RecListWithIDT npcs; RecListT npcChange; RecListT probes; RecListT races; From 046ef39c4a6f756f167147d34f112057c6c9914f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 01:10:00 +0200 Subject: [PATCH 170/185] use camera-relative rendering to prevent precision artifacts when moving far from (0,0,0) --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a35560848..3082cf0d7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -52,6 +52,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + // Due to the huge world size of MW, we'll want camera-relative rendering. + // This prevents precision artifacts when moving very far from the origin. + mRendering.getScene()->setCameraRelativeRendering(true); + // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) From 4949576984cd791de0cc68c1013a15e14ad264a2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 19:03:26 +0200 Subject: [PATCH 171/185] disable some player controls in gui mode --- apps/openmw/mwinput/inputmanager.cpp | 48 +++++++++++++++------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 9b5a9ae30..c2233f626 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -97,34 +97,36 @@ namespace MWInput void toggleSpell() { - DrawState state = player.getDrawState(); - if(state == DrawState_Weapon || state == DrawState_Nothing) - { - player.setDrawState(DrawState_Spell); - std::cout << "Player has now readied his hands for spellcasting!\n"; - } - else - { - player.setDrawState(DrawState_Nothing); - std::cout << "Player does not have any kind of attack ready now.\n"; - } + if (windows.isGuiMode()) return; + DrawState state = player.getDrawState(); + if (state == DrawState_Weapon || state == DrawState_Nothing) + { + player.setDrawState(DrawState_Spell); + std::cout << "Player has now readied his hands for spellcasting!\n"; + } + else + { + player.setDrawState(DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n"; + } } void toggleWeapon() { - DrawState state = player.getDrawState(); - if(state == DrawState_Spell || state == DrawState_Nothing) - { - player.setDrawState(DrawState_Weapon); - std::cout << "Player is now drawing his weapon.\n"; - } - else - { - player.setDrawState(DrawState_Nothing); - std::cout << "Player does not have any kind of attack ready now.\n"; - } + if (windows.isGuiMode()) return; + DrawState state = player.getDrawState(); + if (state == DrawState_Spell || state == DrawState_Nothing) + { + player.setDrawState(DrawState_Weapon); + std::cout << "Player is now drawing his weapon.\n"; + } + else + { + player.setDrawState(DrawState_Nothing); + std::cout << "Player does not have any kind of attack ready now.\n"; + } } void screenshot() @@ -184,11 +186,13 @@ namespace MWInput void toggleAutoMove() { + if (windows.isGuiMode()) return; player.setAutoMove (!player.getAutoMove()); } void toggleWalking() { + if (windows.isGuiMode()) return; player.toggleRunning(); } From aa4a1b675fcc138c5b15f7d031846f2253b62f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 01:08:26 +0200 Subject: [PATCH 172/185] fixed the sky reflection issue --- apps/openmw/mwrender/renderconst.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 44 ++++++++++++++++++----- apps/openmw/mwrender/water.hpp | 9 ++++- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 2c7f9e9ac..c4aa093c0 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -52,6 +52,8 @@ enum VisibilityFlags // Sun glare (not visible in reflection) RV_Glare = 128, + RV_OcclusionQuery = 256, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, /// \todo markers (normally hidden) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3082cf0d7..581973811 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -225,6 +225,8 @@ void RenderingManager::update (float duration){ mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() ); checkUnderwater(); + + mWater->update(); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ if(store->cell->data.flags & store->cell->HasWater){ diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 71cf56dfd..445677808 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -11,7 +11,8 @@ namespace MWRender Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), - mReflectionTarget(0), mActive(1), mToggled(1) + mReflectionTarget(0), mActive(1), mToggled(1), + mReflectionRenderActive(false) { mSky = sky; @@ -81,6 +82,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); + mSceneManager->addRenderQueueListener(this); + // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- @@ -161,6 +164,7 @@ void Water::changeCell(const ESM::Cell* cell) void Water::setHeight(const float height) { mTop = height; + mWaterPlane = Plane(Vector3::UNIT_Y, height); mWaterNode->setPosition(0, height, 0); } @@ -220,17 +224,15 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); mReflectionCamera->setFOVy(mCamera->getFOVy()); + mReflectionRenderActive = true; - // Some messy code to get the skybox to show up at all - // The problem here is that it gets clipped by the water plane - // Therefore scale it up a bit + /// \todo For some reason this camera is delayed for 1 frame, which causes ugly sky reflection behaviour.. + /// to circumvent this we just scale the sky up, so it's not that noticable Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); - mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); - - mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); - mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); + mSky->scaleSky(mCamera->getFarClipDistance() / 5000.f); + mReflectionCamera->enableReflection(mWaterPlane); } } @@ -240,8 +242,9 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mSky->resetSkyPosition(); mSky->scaleSky(1); - mReflectionCamera->disableCustomNearClipPlane(); mReflectionCamera->disableReflection(); + mReflectionCamera->disableCustomNearClipPlane(); + mReflectionRenderActive = false; } } @@ -290,4 +293,27 @@ void Water::updateVisible() mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater); } +void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) +{ + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mReflectionRenderActive) + { + mReflectionCamera->disableCustomNearClipPlane(); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + } +} + +void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) +{ + if (queueGroupId < 20 && mReflectionRenderActive) + { + mReflectionCamera->enableCustomNearClipPlane(mWaterPlane); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + } +} + +void Water::update() +{ +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f14482e2b..c8b8d311e 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,7 +11,7 @@ namespace MWRender { class SkyManager; /// Water rendering - class Water : public Ogre::RenderTargetListener + class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; @@ -27,11 +27,17 @@ namespace MWRender { bool mToggled; int mTop; + bool mReflectionRenderActive; + Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); + void updateVisible(); SkyManager* mSky; @@ -55,6 +61,7 @@ namespace MWRender { void setActive(bool active); void toggle(); + void update(); void setViewportBackground(const Ogre::ColourValue& bg); From fb0e649191270e9c4f4720c2a4983520cf01a632 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 01:10:55 +0200 Subject: [PATCH 173/185] minor fix --- apps/openmw/mwrender/occlusionquery.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 80b804dce..6d3f67de9 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -65,6 +65,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); + mBBQueryTotal->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryTotal); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); @@ -73,6 +74,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); + mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryVisible); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); @@ -82,6 +84,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); + mBBQuerySingleObject->setVisibilityFlags(RV_OcclusionQuery); mObjectNode->attachObject(mBBQuerySingleObject); mRendering->getScene()->addRenderObjectListener(this); From f7a03b39c4db9e50604520e8e552d8a97941a419 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 19 Apr 2012 14:58:27 +0200 Subject: [PATCH 174/185] Some improvments for windows builds and installer --- CMakeLists.txt | 11 ++++++++--- files/openmw.bmp | Bin 0 -> 79926 bytes files/plugins.cfg.win32 | 10 +++++----- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 files/openmw.bmp diff --git a/CMakeLists.txt b/CMakeLists.txt index 40347898b..f3ef797dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,12 +359,17 @@ if(DPKG_PROGRAM) endif(DPKG_PROGRAM) if(WIN32) - FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*") - INSTALL(FILES ${files} DESTINATION ".") + FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") + INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES + "${OpenMW_BINARY_DIR}/plugins.cfg" "${OpenMW_SOURCE_DIR}/readme.txt" + "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" + "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" + "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") @@ -390,7 +395,7 @@ if(WIN32) SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.ico") - # SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") + SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe") if(EXISTS ${VCREDIST32}) diff --git a/files/openmw.bmp b/files/openmw.bmp new file mode 100644 index 0000000000000000000000000000000000000000..be3fd94ce7a55f272e285089fbe7f7966aeaead1 GIT binary patch literal 79926 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 LloqF`2z={b0q!s@ literal 0 HcmV?d00001 diff --git a/files/plugins.cfg.win32 b/files/plugins.cfg.win32 index f71e8d325..ea12c0394 100644 --- a/files/plugins.cfg.win32 +++ b/files/plugins.cfg.win32 @@ -4,10 +4,10 @@ PluginFolder=.\ # Define plugins -Plugin=RenderSystem_Direct3D9_d -Plugin=RenderSystem_GL_d -Plugin=Plugin_ParticleFX_d -Plugin=Plugin_OctreeSceneManager_d -Plugin=Plugin_CgProgramManager_d +Plugin=RenderSystem_Direct3D9 +Plugin=RenderSystem_GL +Plugin=Plugin_ParticleFX +Plugin=Plugin_OctreeSceneManager +Plugin=Plugin_CgProgramManager From c6da3872b443572b5c686eae15d14f4ac35ab8c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 20:59:57 +0200 Subject: [PATCH 175/185] light improvements --- apps/openmw/mwrender/objects.cpp | 134 ++++++++++++---------- apps/openmw/mwrender/objects.hpp | 26 +++-- apps/openmw/mwrender/renderingmanager.cpp | 11 ++ apps/openmw/mwrender/renderingmanager.hpp | 3 + apps/openmw/mwrender/terrainmaterial.cpp | 4 +- apps/openmw/mwworld/scene.cpp | 5 +- 6 files changed, 114 insertions(+), 69 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index eb7e440cb..a79d72989 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -8,20 +8,15 @@ using namespace MWRender; -bool Objects::lightConst = false; -float Objects::lightConstValue = 0.0f; - -bool Objects::lightLinear = true; -int Objects::lightLinearMethod = 1; +// These are the Morrowind.ini defaults float Objects::lightLinearValue = 3; float Objects::lightLinearRadiusMult = 1; -bool Objects::lightQuadratic = false; -int Objects::lightQuadraticMethod = 2; float Objects::lightQuadraticValue = 16; float Objects::lightQuadraticRadiusMult = 1; -bool Objects::lightOutQuadInLin = false; +bool Objects::lightOutQuadInLin = true; +bool Objects::lightQuadratic = false; int Objects::uniqueID = 0; @@ -132,7 +127,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { insert->attachObject(ent); @@ -144,18 +139,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) { Ogre::StaticGeometry* sg = 0; -/* if (transparent) - { - if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end()) - { - uniqueID = uniqueID +1; - sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); - mStaticGeometryAlpha[ptr.getCell()] = sg; - } - else - sg = mStaticGeometryAlpha[ptr.getCell()]; - } - else*/ if (small) + if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { @@ -207,34 +191,35 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f assert(insert); Ogre::Light *light = mRenderer.getScene()->createLight(); light->setDiffuseColour (r, g, b); - mLights.push_back(light->getName()); - float cval=0.0f, lval=0.0f, qval=0.0f; + LightInfo info; + info.name = light->getName(); + info.radius = radius; + info.colour = Ogre::ColourValue(r, g, b); + mLights.push_back(info); + - if(lightConst) - cval = lightConstValue; + bool quadratic = false; + if (!lightOutQuadInLin) + quadratic = lightQuadratic; + else + { + quadratic = !mInterior; + } - if(!lightOutQuadInLin) + if (!quadratic) { - if(lightLinear) - radius *= lightLinearRadiusMult; - if(lightQuadratic) - radius *= lightQuadraticRadiusMult; - - if(lightLinear) - lval = lightLinearValue / pow(radius, lightLinearMethod); - if(lightQuadratic) - qval = lightQuadraticValue / pow(radius, lightQuadraticMethod); + float r = radius * lightLinearRadiusMult; + float attenuation = lightLinearValue / r; + light->setAttenuation(r*10, 0, attenuation, 0); } else { - // FIXME: - // Do quadratic or linear, depending if we're in an exterior or interior - // cell, respectively. Ignore lightLinear and lightQuadratic. + float r = radius * lightQuadraticRadiusMult; + float attenuation = lightQuadraticValue / pow(r, 2); + light->setAttenuation(r*10, 0, 0, attenuation); } - light->setAttenuation(10*radius, cval, lval, qval); - insert->attachObject(light); } @@ -290,13 +275,6 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; } - /*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store]; - mStaticGeometryAlpha.erase(store); - mRenderer.getScene()->destroyStaticGeometry (sg); - sg = 0; - }*/ if(mBounds.find(store) != mBounds.end()) mBounds.erase(store); @@ -314,11 +292,6 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell) Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; sg->build(); } - /*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell]; - sg->build(); - }*/ } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) @@ -328,12 +301,12 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) void Objects::enableLights() { - std::vector::iterator it = mLights.begin(); + std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(*it)) + if (mMwRoot->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(*it)->setVisible(true); + mMwRoot->getCreator()->getLight(it->name)->setVisible(true); ++it; } else @@ -343,12 +316,12 @@ void Objects::enableLights() void Objects::disableLights() { - std::vector::iterator it = mLights.begin(); + std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(*it)) + if (mMwRoot->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(*it)->setVisible(false); + mMwRoot->getCreator()->getLight(it->name)->setVisible(false); ++it; } else @@ -356,3 +329,48 @@ void Objects::disableLights() } } +void Objects::setInterior(const bool interior) +{ + mInterior = interior; +} + +void Objects::update(const float dt) +{ + // adjust the lights depending if we're in an interior or exterior cell + // quadratic means the light intensity falls off quite fast, resulting in a + // dark, atmospheric environment (perfect for exteriors) + // for interiors, we want more "warm" lights, so use linear attenuation. + std::vector::iterator it = mLights.begin(); + while (it != mLights.end()) + { + if (mMwRoot->getCreator()->hasLight(it->name)) + { + Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); + + bool quadratic = false; + if (!lightOutQuadInLin) + quadratic = lightQuadratic; + else + { + quadratic = !mInterior; + } + + if (!quadratic) + { + float radius = it->radius * lightLinearRadiusMult; + float attenuation = lightLinearValue / it->radius; + light->setAttenuation(radius*10, 0, attenuation, 0); + } + else + { + float radius = it->radius * lightQuadraticRadiusMult; + float attenuation = lightQuadraticValue / pow(it->radius, 2); + light->setAttenuation(radius*10, 0, 0, attenuation); + } + + ++it; + } + else + it = mLights.erase(it); + } +} diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 0c19f9f33..63e639ef7 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -10,37 +10,41 @@ namespace MWRender{ +/// information about light needed for rendering +struct LightInfo +{ + std::string name; // ogre handle + Ogre::ColourValue colour; + float radius; +}; + class Objects{ OEngine::Render::OgreRenderer &mRenderer; std::map mCellSceneNodes; std::map mStaticGeometry; std::map mStaticGeometrySmall; - //std::map mStaticGeometryAlpha; std::map mBounds; - std::vector mLights; + std::vector mLights; Ogre::SceneNode* mMwRoot; bool mIsStatic; static int uniqueID; - static bool lightConst; - static float lightConstValue; - static bool lightLinear; - static int lightLinearMethod; static float lightLinearValue; static float lightLinearRadiusMult; static bool lightQuadratic; - static int lightQuadraticMethod; static float lightQuadraticValue; static float lightQuadraticRadiusMult; static bool lightOutQuadInLin; + bool mInterior; + void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer){} + Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mInterior(true) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -49,6 +53,12 @@ public: void enableLights(); void disableLights(); + void update (const float dt); + ///< per-frame update + + void setInterior(const bool interior); + ///< call this to switch from interior to exterior or vice versa + Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 581973811..5232c5140 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -213,6 +213,7 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve void RenderingManager::update (float duration){ mActors.update (duration); + mObjects.update (duration); mOcclusionQuery->update(duration); @@ -508,4 +509,14 @@ Shadows* RenderingManager::getShadows() return mShadows; } +void RenderingManager::switchToInterior() +{ + mObjects.setInterior(true); +} + +void RenderingManager::switchToExterior() +{ + mObjects.setInterior(false); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a563d78c6..cc3bc62b5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -117,6 +117,9 @@ class RenderingManager: private RenderingInterface { Shadows* getShadows(); + void switchToInterior(); + void switchToExterior(); + void setGlare(bool glare); void skyEnable (); void skyDisable (); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 9785ec903..a3265b2a5 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -1149,8 +1149,8 @@ namespace Ogre // simple per-pixel lighting with no normal mapping for (int i=0; igetNumberOfLightsSupported(); ++i) { - outStream << " float3 halfAngle"< 0) outStream << diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2123b4799..c8b20b8b1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -203,6 +203,8 @@ namespace MWWorld // Sky system mWorld->adjustSky(); + mRendering.switchToExterior(); + mCellChanged = true; } @@ -248,8 +250,9 @@ namespace MWWorld // adjust player mCurrentCell = cell; playerCellChange (cell, position); - + // adjust fog + mRendering.switchToInterior(); mRendering.configureFog(*cell); // Sky system From 7400b7f313d8cbc7141ca89d926be3dc42dca9be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 23:25:58 +0200 Subject: [PATCH 176/185] fix underwater effect staying active when teleporting from underwater to a cell that doesn't have water --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5232c5140..3f1bb924f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -512,11 +512,13 @@ Shadows* RenderingManager::getShadows() void RenderingManager::switchToInterior() { mObjects.setInterior(true); + mRendering.getScene()->setCameraRelativeRendering(false); } void RenderingManager::switchToExterior() { mObjects.setInterior(false); + mRendering.getScene()->setCameraRelativeRendering(true); } } // namespace diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 445677808..c81f23f54 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -176,7 +176,12 @@ void Water::toggle() void Water::checkUnderwater(float y) { - if (!mActive) return; + if (!mActive) + { + CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + return; + } + if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); From cc86998281f03898859c8c4b83ccf223b0a44568 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 21 Apr 2012 10:12:59 +0200 Subject: [PATCH 177/185] removing some cout spam --- apps/openmw/mwdialogue/dialoguemanager.cpp | 1 - apps/openmw/mwrender/npcanimation.cpp | 1 - apps/openmw/mwworld/inventorystore.cpp | 12 +----------- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 90f0c0231..e9cb3d33e 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -677,7 +677,6 @@ namespace MWDialogue void DialogueManager::executeScript(std::string script) { - std::cout << script; std::vector code; if(compile(script,code)) { diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 751a07548..3d760f28e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -159,7 +159,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); else insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); - std::cout << "Inv" << inv.getStateId() << "\n"; updateParts(); } diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 230f7d69a..7d6be4dd7 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -8,8 +8,6 @@ #include "class.hpp" -#include /// \todo remove after rendering is implemented - void MWWorld::InventoryStore::copySlots (const InventoryStore& store) { // some const-trickery, required because of a flaw in the handling of MW-references and the @@ -72,7 +70,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite /// \todo restack item previously in this slot (if required) /// \todo unstack item pointed to by iterator if required) - + mSlots[slot] = iterator; flagAsModified(); @@ -169,13 +167,5 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats, { mSlots.swap (slots); flagAsModified(); - - /// \todo remove the following line after rendering is implemented - for (std::size_t i=0; i Date: Mon, 23 Apr 2012 10:57:16 +0200 Subject: [PATCH 178/185] Issue #255: added new environment class (not in use yet) --- apps/openmw/CMakeLists.txt | 4 + apps/openmw/mwbase/environment.cpp | 123 +++++++++++++++++++++++++++++ apps/openmw/mwbase/environment.hpp | 117 +++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 apps/openmw/mwbase/environment.cpp create mode 100644 apps/openmw/mwbase/environment.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c4b3776ed..a27d5ae75 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -58,6 +58,10 @@ add_openmw_dir (mwmechanics mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells ) +add_openmw_dir (mwbase + environment + ) + # Main executable IF(OGRE_STATIC) IF(WIN32) diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp new file mode 100644 index 000000000..43e726e7c --- /dev/null +++ b/apps/openmw/mwbase/environment.cpp @@ -0,0 +1,123 @@ + +#include "environment.hpp" + +#include + +MWBase::Environment *MWBase::Environment::sThis = 0; + +MWBase::Environment::Environment() +: mWorld (0), mSoundManager (0), mGlobalScripts (0), mScriptManager (0), mWindowManager (0), + mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0) +{ + assert (!sThis); + sThis = this; +} + +MWBase::Environment::~Environment() +{ + sThis = 0; +} + +void MWBase::Environment::setWorld (MWWorld::World *world) +{ + mWorld = world; +} + +void MWBase::Environment::setSoundManager (MWSound::SoundManager *soundManager) +{ + mSoundManager = soundManager; +} + +void MWBase::Environment::setGlobalScripts (MWScript::GlobalScripts *globalScripts) +{ + mGlobalScripts = globalScripts; +} + +void MWBase::Environment::setScriptManager (MWScript::ScriptManager *scriptManager) +{ + mScriptManager = scriptManager; +} + +void MWBase::Environment::setWindowManager (MWGui::WindowManager *windowManager) +{ + mWindowManager = windowManager; +} + +void MWBase::Environment::setMechanicsManager (MWMechanics::MechanicsManager *mechanicsManager) +{ + mMechanicsManager = mechanicsManager; +} + +void MWBase::Environment::setDialogueManager (MWDialogue::DialogueManager *dialogueManager) +{ + mDialogueManager = dialogueManager; +} + +void MWBase::Environment::setJournal (MWDialogue::Journal *journal) +{ + mJournal = journal; +} + +void MWBase::Environment::setFrameDuration (float duration) +{ + mFrameDuration = duration; +} + +MWWorld::World *MWBase::Environment::getWorld() const +{ + assert (mWorld); + return mWorld; +} + +MWSound::SoundManager *MWBase::Environment::getSoundManager() const +{ + assert (mSoundManager); + return mSoundManager; +} + +MWScript::GlobalScripts *MWBase::Environment::getGlobalScripts() const +{ + assert (mGlobalScripts); + return mGlobalScripts; +} + +MWScript::ScriptManager *MWBase::Environment::getScriptManager() const +{ + assert (mScriptManager); + return mScriptManager; +} + +MWGui::WindowManager *MWBase::Environment::getWindowManager() const +{ + assert (mWindowManager); + return mWindowManager; +} + +MWMechanics::MechanicsManager *MWBase::Environment::getMechanicsManager() const +{ + assert (mMechanicsManager); + return mMechanicsManager; +} + +MWDialogue::DialogueManager *MWBase::Environment::getDialogueManager() const +{ + assert (mDialogueManager); + return mDialogueManager; +} + +MWDialogue::Journal *MWBase::Environment::getJournal() const +{ + assert (mJournal); + return mJournal; +} + +float MWBase::Environment::getFrameDuration() const +{ + return mFrameDuration; +} + +const MWBase::Environment& MWBase::Environment::get() +{ + assert (sThis); + return *sThis; +} diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp new file mode 100644 index 000000000..9fca70435 --- /dev/null +++ b/apps/openmw/mwbase/environment.hpp @@ -0,0 +1,117 @@ +#ifndef GAME_BASE_INVIRONMENT_H +#define GAME_BASE_INVIRONMENT_H + +namespace MWSound +{ + class SoundManager; +} + +namespace MWScript +{ + class GlobalScripts; + class ScriptManager; +} + +namespace MWGui +{ + class WindowManager; +} + +namespace MWMechanics +{ + class MechanicsManager; +} + +namespace MWDialogue +{ + class DialogueManager; + class Journal; +} + +namespace MWInput +{ + struct MWInputManager; +} + +namespace MWWorld +{ + class World; +} + +namespace MWBase +{ + /// \brief Central hub for mw-subsystems + /// + /// This class allows each mw-subsystem to access any others subsystem's top-level manager class. + /// + /// \attention Environment does not take ownership of the manager class instances it is handed over in + /// the set* functions. + class Environment + { + static Environment *sThis; + + MWWorld::World *mWorld; + MWSound::SoundManager *mSoundManager; + MWScript::GlobalScripts *mGlobalScripts; + MWScript::ScriptManager *mScriptManager; + MWGui::WindowManager *mWindowManager; + MWMechanics::MechanicsManager *mMechanicsManager; + MWDialogue::DialogueManager *mDialogueManager; + MWDialogue::Journal *mJournal; + float mFrameDuration; + + Environment (const Environment&); + ///< not implemented + + Environment& operator= (const Environment&); + ///< not implemented + + public: + + Environment(); + + ~Environment(); + + void setWorld (MWWorld::World *world); + + void setSoundManager (MWSound::SoundManager *soundManager); + + void setGlobalScripts (MWScript::GlobalScripts *globalScripts); + + void setScriptManager (MWScript::ScriptManager *scriptManager); + + void setWindowManager (MWGui::WindowManager *windowManager); + + void setMechanicsManager (MWMechanics::MechanicsManager *mechanicsManager); + + void setDialogueManager (MWDialogue::DialogueManager *dialogueManager); + + void setJournal (MWDialogue::Journal *journal); + + void setFrameDuration (float duration); + ///< Set length of current frame in seconds. + + MWWorld::World *getWorld() const; + + MWSound::SoundManager *getSoundManager() const; + + MWScript::GlobalScripts *getGlobalScripts() const; + + MWScript::ScriptManager *getScriptManager() const; + + MWGui::WindowManager *getWindowManager() const; + + MWMechanics::MechanicsManager *getMechanicsManager() const; + + MWDialogue::DialogueManager *getDialogueManager() const; + + MWDialogue::Journal *getJournal() const; + + float getFrameDuration() const; + + static const Environment& get(); + ///< Return instance of this class. + }; +} + +#endif From 7102a825c265ac8d6d43152ccb963731859a7709 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Apr 2012 11:15:47 +0200 Subject: [PATCH 179/185] Issue 255: moved global scripts into script manager (simplifying the environment class) --- apps/openmw/engine.cpp | 8 ++------ apps/openmw/mwbase/environment.cpp | 13 +------------ apps/openmw/mwbase/environment.hpp | 6 ------ apps/openmw/mwscript/interpretercontext.cpp | 7 ++++--- apps/openmw/mwscript/scriptmanager.cpp | 7 ++++++- apps/openmw/mwscript/scriptmanager.hpp | 6 +++++- apps/openmw/mwworld/environment.hpp | 4 +--- 7 files changed, 19 insertions(+), 32 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2d3c872dd..ef1497905 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -142,7 +142,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); // global scripts - mEnvironment.mGlobalScripts->run (mEnvironment); + mEnvironment.mScriptManager->getGlobalScripts().run (mEnvironment); bool changed = mEnvironment.mWorld->hasCellChanged(); @@ -205,7 +205,6 @@ OMW::Engine::~Engine() { delete mEnvironment.mWorld; delete mEnvironment.mSoundManager; - delete mEnvironment.mGlobalScripts; delete mEnvironment.mMechanicsManager; delete mEnvironment.mDialogueManager; delete mEnvironment.mJournal; @@ -219,7 +218,7 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); - + for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter) { std::cout << "Adding " << iter->second.string() << std::endl; @@ -402,9 +401,6 @@ void OMW::Engine::go() mEnvironment.mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), mVerboseScripts, *mScriptContext); - mEnvironment.mGlobalScripts = new MWScript::GlobalScripts (mEnvironment.mWorld->getStore(), - *mEnvironment.mScriptManager); - // Create game mechanics system mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 43e726e7c..084505171 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -6,7 +6,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() -: mWorld (0), mSoundManager (0), mGlobalScripts (0), mScriptManager (0), mWindowManager (0), +: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0) { assert (!sThis); @@ -28,11 +28,6 @@ void MWBase::Environment::setSoundManager (MWSound::SoundManager *soundManager) mSoundManager = soundManager; } -void MWBase::Environment::setGlobalScripts (MWScript::GlobalScripts *globalScripts) -{ - mGlobalScripts = globalScripts; -} - void MWBase::Environment::setScriptManager (MWScript::ScriptManager *scriptManager) { mScriptManager = scriptManager; @@ -75,12 +70,6 @@ MWSound::SoundManager *MWBase::Environment::getSoundManager() const return mSoundManager; } -MWScript::GlobalScripts *MWBase::Environment::getGlobalScripts() const -{ - assert (mGlobalScripts); - return mGlobalScripts; -} - MWScript::ScriptManager *MWBase::Environment::getScriptManager() const { assert (mScriptManager); diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 9fca70435..1b1ace0c7 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -8,7 +8,6 @@ namespace MWSound namespace MWScript { - class GlobalScripts; class ScriptManager; } @@ -52,7 +51,6 @@ namespace MWBase MWWorld::World *mWorld; MWSound::SoundManager *mSoundManager; - MWScript::GlobalScripts *mGlobalScripts; MWScript::ScriptManager *mScriptManager; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; @@ -76,8 +74,6 @@ namespace MWBase void setSoundManager (MWSound::SoundManager *soundManager); - void setGlobalScripts (MWScript::GlobalScripts *globalScripts); - void setScriptManager (MWScript::ScriptManager *scriptManager); void setWindowManager (MWGui::WindowManager *windowManager); @@ -95,8 +91,6 @@ namespace MWBase MWSound::SoundManager *getSoundManager() const; - MWScript::GlobalScripts *getGlobalScripts() const; - MWScript::ScriptManager *getScriptManager() const; MWGui::WindowManager *getWindowManager() const; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 258493782..acd1d957d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -15,6 +15,7 @@ #include "locals.hpp" #include "globalscripts.hpp" +#include "scriptmanager.hpp" namespace MWScript { @@ -174,17 +175,17 @@ namespace MWScript bool InterpreterContext::isScriptRunning (const std::string& name) const { - return mEnvironment.mGlobalScripts->isRunning (name); + return mEnvironment.mScriptManager->getGlobalScripts().isRunning (name); } void InterpreterContext::startScript (const std::string& name) { - mEnvironment.mGlobalScripts->addScript (name); + mEnvironment.mScriptManager->getGlobalScripts().addScript (name); } void InterpreterContext::stopScript (const std::string& name) { - mEnvironment.mGlobalScripts->removeScript (name); + mEnvironment.mScriptManager->getGlobalScripts().removeScript (name); } float InterpreterContext::getDistance (const std::string& name, const std::string& id) const diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index e93f2deec..506cf049c 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -20,7 +20,7 @@ namespace MWScript Compiler::Context& compilerContext) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), - mOpcodesInstalled (false) + mOpcodesInstalled (false), mGlobalScripts (store, *this) {} bool ScriptManager::compile (const std::string& name) @@ -151,4 +151,9 @@ namespace MWScript return iter->second.second; } + + GlobalScripts& ScriptManager::getGlobalScripts() + { + return mGlobalScripts; + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index 35cbc0d1e..35c1fadd9 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -11,6 +11,8 @@ #include #include +#include "globalscripts.hpp" + namespace ESMS { struct ESMStore; @@ -42,8 +44,8 @@ namespace MWScript typedef std::pair, Compiler::Locals> CompiledScript; typedef std::map ScriptCollection; - ScriptCollection mScripts; + GlobalScripts mGlobalScripts; public: @@ -63,6 +65,8 @@ namespace MWScript Compiler::Locals& getLocals (const std::string& name); ///< Return locals for script \a name. + + GlobalScripts& getGlobalScripts(); }; }; diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index 3a83f886f..8c4a001e0 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -8,7 +8,6 @@ namespace MWSound namespace MWScript { - class GlobalScripts; class ScriptManager; } @@ -42,14 +41,13 @@ namespace MWWorld { public: Environment() - : mWorld (0), mSoundManager (0), mGlobalScripts (0), mScriptManager (0), mWindowManager (0), + : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), mInputManager (0) {} World *mWorld; MWSound::SoundManager *mSoundManager; - MWScript::GlobalScripts *mGlobalScripts; MWScript::ScriptManager *mScriptManager; MWGui::WindowManager *mWindowManager; MWMechanics::MechanicsManager *mMechanicsManager; From 35f478071e8ea81bff6b2e06ca14970e796752c7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Apr 2012 15:27:03 +0200 Subject: [PATCH 180/185] Issue #255: deleted the old environment class and using the new one instead --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/engine.cpp | 120 +++++++++---------- apps/openmw/engine.hpp | 5 +- apps/openmw/mwbase/environment.cpp | 13 +- apps/openmw/mwbase/environment.hpp | 5 + apps/openmw/mwclass/activator.cpp | 4 +- apps/openmw/mwclass/activator.hpp | 2 +- apps/openmw/mwclass/apparatus.cpp | 9 +- apps/openmw/mwclass/apparatus.hpp | 4 +- apps/openmw/mwclass/armor.cpp | 26 ++-- apps/openmw/mwclass/armor.hpp | 11 +- apps/openmw/mwclass/book.cpp | 13 +- apps/openmw/mwclass/book.hpp | 8 +- apps/openmw/mwclass/clothing.cpp | 16 +-- apps/openmw/mwclass/clothing.hpp | 11 +- apps/openmw/mwclass/container.cpp | 11 +- apps/openmw/mwclass/container.hpp | 4 +- apps/openmw/mwclass/creature.cpp | 15 +-- apps/openmw/mwclass/creature.hpp | 8 +- apps/openmw/mwclass/door.cpp | 17 +-- apps/openmw/mwclass/door.hpp | 4 +- apps/openmw/mwclass/ingredient.cpp | 13 +- apps/openmw/mwclass/ingredient.hpp | 8 +- apps/openmw/mwclass/light.cpp | 17 +-- apps/openmw/mwclass/light.hpp | 10 +- apps/openmw/mwclass/lockpick.cpp | 13 +- apps/openmw/mwclass/lockpick.hpp | 8 +- apps/openmw/mwclass/misc.cpp | 13 +- apps/openmw/mwclass/misc.hpp | 8 +- apps/openmw/mwclass/npc.cpp | 21 ++-- apps/openmw/mwclass/npc.hpp | 8 +- apps/openmw/mwclass/potion.cpp | 13 +- apps/openmw/mwclass/potion.hpp | 8 +- apps/openmw/mwclass/probe.cpp | 13 +- apps/openmw/mwclass/probe.hpp | 8 +- apps/openmw/mwclass/repair.cpp | 13 +- apps/openmw/mwclass/repair.hpp | 8 +- apps/openmw/mwclass/static.cpp | 2 +- apps/openmw/mwclass/static.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 16 +-- apps/openmw/mwclass/weapon.hpp | 11 +- apps/openmw/mwdialogue/dialoguemanager.cpp | 56 ++++----- apps/openmw/mwdialogue/dialoguemanager.hpp | 11 +- apps/openmw/mwdialogue/journal.cpp | 17 ++- apps/openmw/mwdialogue/journal.hpp | 8 +- apps/openmw/mwgui/charactercreation.cpp | 27 +++-- apps/openmw/mwgui/charactercreation.hpp | 3 +- apps/openmw/mwgui/console.cpp | 21 ++-- apps/openmw/mwgui/console.hpp | 3 +- apps/openmw/mwgui/dialogue.cpp | 17 ++- apps/openmw/mwgui/dialogue.hpp | 9 +- apps/openmw/mwgui/journalwindow.cpp | 18 +-- apps/openmw/mwgui/window_manager.cpp | 24 ++-- apps/openmw/mwgui/window_manager.hpp | 6 +- apps/openmw/mwmechanics/actors.cpp | 4 +- apps/openmw/mwmechanics/actors.hpp | 8 +- apps/openmw/mwmechanics/mechanicsmanager.cpp | 67 ++++++----- apps/openmw/mwmechanics/mechanicsmanager.hpp | 8 +- apps/openmw/mwmechanics/spells.cpp | 7 +- apps/openmw/mwmechanics/spells.hpp | 7 +- apps/openmw/mwrender/actors.cpp | 8 +- apps/openmw/mwrender/actors.hpp | 4 +- apps/openmw/mwrender/animation.cpp | 5 +- apps/openmw/mwrender/animation.hpp | 20 ++-- apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/creatureanimation.hpp | 9 +- apps/openmw/mwrender/debugging.cpp | 8 +- apps/openmw/mwrender/debugging.hpp | 4 +- apps/openmw/mwrender/localmap.cpp | 27 ++--- apps/openmw/mwrender/localmap.hpp | 8 +- apps/openmw/mwrender/npcanimation.cpp | 66 +++++----- apps/openmw/mwrender/npcanimation.hpp | 17 ++- apps/openmw/mwrender/renderingmanager.cpp | 13 +- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/sky.cpp | 19 ++- apps/openmw/mwrender/sky.hpp | 9 +- apps/openmw/mwrender/terrain.cpp | 14 ++- apps/openmw/mwrender/terrain.hpp | 3 +- apps/openmw/mwscript/animationextensions.cpp | 15 +-- apps/openmw/mwscript/cellextensions.cpp | 58 +++------ apps/openmw/mwscript/compilercontext.cpp | 58 ++++----- apps/openmw/mwscript/compilercontext.hpp | 30 ++--- apps/openmw/mwscript/containerextensions.cpp | 7 +- apps/openmw/mwscript/controlextensions.cpp | 4 +- apps/openmw/mwscript/dialogueextensions.cpp | 29 ++--- apps/openmw/mwscript/globalscripts.cpp | 29 +++-- apps/openmw/mwscript/globalscripts.hpp | 20 ++-- apps/openmw/mwscript/guiextensions.cpp | 19 +-- apps/openmw/mwscript/interpretercontext.cpp | 85 +++++-------- apps/openmw/mwscript/interpretercontext.hpp | 17 +-- apps/openmw/mwscript/miscextensions.cpp | 28 ++--- apps/openmw/mwscript/ref.hpp | 7 +- apps/openmw/mwscript/skyextensions.cpp | 48 +++----- apps/openmw/mwscript/soundextensions.cpp | 44 ++----- apps/openmw/mwscript/statsextensions.cpp | 30 ++--- apps/openmw/mwsound/soundmanager.cpp | 16 +-- apps/openmw/mwsound/soundmanager.hpp | 9 +- apps/openmw/mwworld/action.hpp | 4 +- apps/openmw/mwworld/actiontake.cpp | 9 +- apps/openmw/mwworld/actiontake.hpp | 2 +- apps/openmw/mwworld/actiontalk.cpp | 6 +- apps/openmw/mwworld/actiontalk.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 9 +- apps/openmw/mwworld/actionteleport.hpp | 2 +- apps/openmw/mwworld/class.cpp | 18 ++- apps/openmw/mwworld/class.hpp | 18 ++- apps/openmw/mwworld/environment.hpp | 63 ---------- apps/openmw/mwworld/inventorystore.cpp | 9 +- apps/openmw/mwworld/inventorystore.hpp | 4 +- apps/openmw/mwworld/nullaction.hpp | 2 +- apps/openmw/mwworld/scene.cpp | 77 ++++++------ apps/openmw/mwworld/scene.hpp | 6 +- apps/openmw/mwworld/weather.cpp | 63 +++++----- apps/openmw/mwworld/weather.hpp | 107 ++++++++--------- apps/openmw/mwworld/world.cpp | 23 ++-- apps/openmw/mwworld/world.hpp | 4 +- 116 files changed, 891 insertions(+), 1170 deletions(-) delete mode 100644 apps/openmw/mwworld/environment.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a27d5ae75..fb0e1db69 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwsound ) add_openmw_dir (mwworld - refdata world physicssystem scene environment globals class action nullaction actionteleport + refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr ) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ef1497905..4ae6ae747 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -50,10 +50,12 @@ #include "mwmechanics/mechanicsmanager.hpp" +#include "mwbase/environment.hpp" + void OMW::Engine::executeLocalScripts() { - MWWorld::LocalScripts& localScripts = mEnvironment.mWorld->getLocalScripts(); + MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); localScripts.startIteration(); @@ -61,11 +63,11 @@ void OMW::Engine::executeLocalScripts() { std::pair script = localScripts.getNext(); - MWScript::InterpreterContext interpreterContext (mEnvironment, + MWScript::InterpreterContext interpreterContext ( &script.second.getRefData().getLocals(), script.second); - mEnvironment.mScriptManager->run (script.first, interpreterContext); + MWBase::Environment::get().getScriptManager()->run (script.first, interpreterContext); - if (mEnvironment.mWorld->hasCellChanged()) + if (MWBase::Environment::get().getWorld()->hasCellChanged()) break; } @@ -81,7 +83,7 @@ void OMW::Engine::updateFocusReport (float duration) std::string name; - std::string handle = mEnvironment.mWorld->getFacedHandle(); + std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); if (!handle.empty()) { @@ -90,7 +92,7 @@ void OMW::Engine::updateFocusReport (float duration) // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case try { - MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); if (!ptr.isEmpty()){ name = MWWorld::Class::get (ptr).getName (ptr); @@ -124,27 +126,27 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { - mEnvironment.mFrameDuration = evt.timeSinceLastFrame; + mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input - mEnvironment.mInputManager->update(); + MWBase::Environment::get().getInputManager()->update(); // sound if (mUseSound) - mEnvironment.mSoundManager->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); - mEnvironment.mWindowManager->wmUpdateFps(window->getLastFPS(), + MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), window->getTriangleCount(), window->getBatchCount()); - mEnvironment.mWindowManager->onFrame(mEnvironment.mFrameDuration); + MWBase::Environment::get().getWindowManager()->onFrame(mEnvironment.getFrameDuration()); // global scripts - mEnvironment.mScriptManager->getGlobalScripts().run (mEnvironment); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); - bool changed = mEnvironment.mWorld->hasCellChanged(); + bool changed = MWBase::Environment::get().getWorld()->hasCellChanged(); // local scripts executeLocalScripts(); // This does not handle the case where a global script causes a cell @@ -152,28 +154,28 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // frame. // passing of time - if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game) - mEnvironment.mWorld->advanceTime ( - mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600); + if (MWBase::Environment::get().getWindowManager()->getMode()==MWGui::GM_Game) + MWBase::Environment::get().getWorld()->advanceTime ( + mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); if (changed) // keep change flag for another frame, if cell changed happend in local script - mEnvironment.mWorld->markCellAsUnchanged(); + MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors std::vector > movement; - mEnvironment.mMechanicsManager->update (movement, mEnvironment.mFrameDuration, - mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game); + MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(), + MWBase::Environment::get().getWindowManager()->getMode()!=MWGui::GM_Game); - if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game) - mEnvironment.mWorld->doPhysics (movement, mEnvironment.mFrameDuration); + if (MWBase::Environment::get().getWindowManager()->getMode()==MWGui::GM_Game) + MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); // update world - mEnvironment.mWorld->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame); // report focus object (for debugging) if (mReportFocus) - updateFocusReport (mEnvironment.mFrameDuration); + updateFocusReport (mEnvironment.getFrameDuration()); } catch (const std::exception& e) { @@ -203,12 +205,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) OMW::Engine::~Engine() { - delete mEnvironment.mWorld; - delete mEnvironment.mSoundManager; - delete mEnvironment.mMechanicsManager; - delete mEnvironment.mDialogueManager; - delete mEnvironment.mJournal; - delete mEnvironment.mScriptManager; + delete MWBase::Environment::get().getInputManager(); + delete MWBase::Environment::get().getSoundManager(); + delete MWBase::Environment::get().getMechanicsManager(); + delete MWBase::Environment::get().getDialogueManager(); + delete MWBase::Environment::get().getJournal(); + delete MWBase::Environment::get().getScriptManager(); + delete MWBase::Environment::get().getWorld(); delete mScriptContext; delete mOgre; } @@ -312,7 +315,6 @@ void OMW::Engine::setReportFocus (bool report) void OMW::Engine::go() { mFocusTDiff = 0; - assert (!mEnvironment.mWorld); assert (!mCellName.empty()); assert (!mMaster.empty()); assert (!mOgre); @@ -381,66 +383,66 @@ void OMW::Engine::go() MWGui::CursorReplace replacer; // Create the world - mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mNewGame, mEnvironment, mEncoding, mFallbackMap); + mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, + mResDir, mNewGame, mEncoding, mFallbackMap)); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); - mEnvironment.mWindowManager = new MWGui::WindowManager(mEnvironment, - mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/")); + mEnvironment.setWindowManager (new MWGui::WindowManager( + mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"))); // Create sound system - mEnvironment.mSoundManager = new MWSound::SoundManager(mUseSound, mEnvironment); + mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); // Create script system - mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full, - mEnvironment); + mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); - mEnvironment.mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), - mVerboseScripts, *mScriptContext); + mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(), + mVerboseScripts, *mScriptContext)); // Create game mechanics system - mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment); + mEnvironment.setMechanicsManager (new MWMechanics::MechanicsManager); // Create dialog system - mEnvironment.mJournal = new MWDialogue::Journal (mEnvironment); - mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment,mExtensions); + mEnvironment.setJournal (new MWDialogue::Journal); + mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions)); // load cell ESM::Position pos; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[2] = 0; - if (const ESM::Cell *exterior = mEnvironment.mWorld->getExterior (mCellName)) + if (const ESM::Cell *exterior = MWBase::Environment::get().getWorld()->getExterior (mCellName)) { - mEnvironment.mWorld->indexToPosition (exterior->data.gridX, exterior->data.gridY, + MWBase::Environment::get().getWorld()->indexToPosition (exterior->data.gridX, exterior->data.gridY, pos.pos[0], pos.pos[1], true); - mEnvironment.mWorld->changeToExteriorCell (pos); + MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); } else { pos.pos[0] = pos.pos[1] = 0; - mEnvironment.mWorld->changeToInteriorCell (mCellName, pos); + MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); } // Sets up the input system - MWInput::MWInputManager input(*mOgre, mEnvironment.mWorld->getPlayer(), - *mEnvironment.mWindowManager, mDebug, *this); - mEnvironment.mInputManager = &input; + + mEnvironment.setInputManager (new MWInput::MWInputManager (*mOgre, + MWBase::Environment::get().getWorld()->getPlayer(), + *MWBase::Environment::get().getWindowManager(), mDebug, *this)); std::cout << "\nPress Q/ESC or close window to exit.\n"; mOgre->getRoot()->addFrameListener (this); // Play some good 'ol tunes - mEnvironment.mSoundManager->playPlaylist(std::string("Explore")); + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); // scripts if (mCompileAll) { - std::pair result = mEnvironment.mScriptManager->compileAll(); + std::pair result = MWBase::Environment::get().getScriptManager()->compileAll(); if (result.first) std::cout @@ -461,10 +463,10 @@ void OMW::Engine::go() void OMW::Engine::activate() { - if (mEnvironment.mWindowManager->getMode()!=MWGui::GM_Game) + if (MWBase::Environment::get().getWindowManager()->getMode()!=MWGui::GM_Game) return; - std::string handle = mEnvironment.mWorld->getFacedHandle(); + std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); if (handle.empty()) return; @@ -475,7 +477,7 @@ void OMW::Engine::activate() MWWorld::Ptr ptr; try { - ptr = mEnvironment.mWorld->getPtrViaHandle (handle); + ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); if (ptr.isEmpty()) return; @@ -485,12 +487,10 @@ void OMW::Engine::activate() return; } - MWScript::InterpreterContext interpreterContext (mEnvironment, - &ptr.getRefData().getLocals(), ptr); + MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); boost::shared_ptr action = - MWWorld::Class::get (ptr).activate (ptr, mEnvironment.mWorld->getPlayer().getPlayer(), - mEnvironment); + MWWorld::Class::get (ptr).activate (ptr, MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); interpreterContext.activate (ptr, action); @@ -498,8 +498,8 @@ void OMW::Engine::activate() if (!script.empty()) { - mEnvironment.mWorld->getLocalScripts().setIgnore (ptr); - mEnvironment.mScriptManager->run (script, interpreterContext); + MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); } if (!interpreterContext.hasActivationBeenHandled()) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 6eae20cc0..ccd7314cb 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -10,7 +10,8 @@ #include #include -#include "mwworld/environment.hpp" +#include "mwbase/environment.hpp" + #include "mwworld/ptr.hpp" namespace Compiler @@ -78,7 +79,7 @@ namespace OMW std::string mFocusName; std::map mFallbackMap; - MWWorld::Environment mEnvironment; + MWBase::Environment mEnvironment; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 084505171..8e9a9cfce 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -7,7 +7,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0; MWBase::Environment::Environment() : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), - mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0) + mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mFrameDuration (0) { assert (!sThis); sThis = this; @@ -53,6 +53,11 @@ void MWBase::Environment::setJournal (MWDialogue::Journal *journal) mJournal = journal; } +void MWBase::Environment::setInputManager (MWInput::MWInputManager *inputManager) +{ + mInputManager = inputManager; +} + void MWBase::Environment::setFrameDuration (float duration) { mFrameDuration = duration; @@ -100,6 +105,12 @@ MWDialogue::Journal *MWBase::Environment::getJournal() const return mJournal; } +MWInput::MWInputManager *MWBase::Environment::getInputManager() const +{ + assert (mInputManager); + return mInputManager; +} + float MWBase::Environment::getFrameDuration() const { return mFrameDuration; diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 1b1ace0c7..a010e7faa 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -56,6 +56,7 @@ namespace MWBase MWMechanics::MechanicsManager *mMechanicsManager; MWDialogue::DialogueManager *mDialogueManager; MWDialogue::Journal *mJournal; + MWInput::MWInputManager *mInputManager; float mFrameDuration; Environment (const Environment&); @@ -84,6 +85,8 @@ namespace MWBase void setJournal (MWDialogue::Journal *journal); + void setInputManager (MWInput::MWInputManager *inputManager); + void setFrameDuration (float duration); ///< Set length of current frame in seconds. @@ -101,6 +104,8 @@ namespace MWBase MWDialogue::Journal *getJournal() const; + MWInput::MWInputManager *getInputManager() const; + float getFrameDuration() const; static const Environment& get(); diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 6749a2bfd..5b5028f1c 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -18,7 +18,7 @@ namespace MWClass assert (ref->base != NULL); const std::string &model = ref->base->model; - + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); @@ -27,7 +27,7 @@ namespace MWClass } } - void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 08be8a5ff..d0b1f25e0 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -12,7 +12,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 90db40b5a..e7c208d4a 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -54,9 +55,9 @@ namespace MWClass } boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 861610f6c..9015aedb8 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 8e1f81136..3a3403261 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -9,11 +9,11 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" - #include "../mwworld/inventorystore.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + #include "../mwrender/objects.hpp" #include "../mwsound/soundmanager.hpp" @@ -36,7 +36,7 @@ namespace MWClass } } - void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -58,9 +58,9 @@ namespace MWClass } boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -121,7 +121,7 @@ namespace MWClass return std::make_pair (slots, false); } - int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -147,13 +147,13 @@ namespace MWClass if (typeGmst.empty()) return -1; - float iWeight = environment.mWorld->getStore().gameSettings.find (typeGmst)->i; + float iWeight = MWBase::Environment::get().getWorld()->getStore().gameSettings.find (typeGmst)->i; - if (iWeight * environment.mWorld->getStore().gameSettings.find ("fLightMaxMod")->f>= + if (iWeight * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fLightMaxMod")->f>= ref->base->data.weight) return ESM::Skill::LightArmor; - if (iWeight * environment.mWorld->getStore().gameSettings.find ("fMedMaxMod")->f>= + if (iWeight * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMedMaxMod")->f>= ref->base->data.weight) return ESM::Skill::MediumArmor; @@ -175,9 +175,9 @@ namespace MWClass registerClass (typeid (ESM::Armor).name(), instance); } - std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Armor::getUpSoundId (const MWWorld::Ptr& ptr) const { - int es = getEquipmentSkill(ptr, environment); + int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) return std::string("Item Armor Light Up"); else if (es == ESM::Skill::MediumArmor) @@ -186,9 +186,9 @@ namespace MWClass return std::string("Item Armor Heavy Up"); } - std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Armor::getDownSoundId (const MWWorld::Ptr& ptr) const { - int es = getEquipmentSkill(ptr, environment); + int es = getEquipmentSkill(ptr); if (es == ESM::Skill::LightArmor) return std::string("Item Armor Light Down"); else if (es == ESM::Skill::MediumArmor) diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index de5ca3983..6cba07726 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; @@ -35,8 +35,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, - const MWWorld::Environment& environment) const; + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. @@ -45,10 +44,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9069d9476..b3b71104b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -54,11 +55,11 @@ namespace MWClass } boost::shared_ptr Book::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { // TODO implement reading - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -87,12 +88,12 @@ namespace MWClass registerClass (typeid (ESM::Book).name(), instance); } - std::string Book::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Book::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Book Up"); } - std::string Book::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Book::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Book Down"); } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 4738187cd..975cdf12b 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -30,10 +30,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 672a2b60a..15f00bb05 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" @@ -32,7 +33,7 @@ namespace MWClass } } - void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -55,9 +56,9 @@ namespace MWClass } boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -111,8 +112,7 @@ namespace MWClass return std::make_pair (slots, false); } - int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr, - const MWWorld::Environment& environment) const + int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -138,7 +138,7 @@ namespace MWClass registerClass (typeid (ESM::Clothing).name(), instance); } - std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -150,7 +150,7 @@ namespace MWClass return std::string("Item Clothes Up"); } - std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 97e09012d..7fc05bef3 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -29,8 +29,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, - const MWWorld::Environment& environment) const; + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. @@ -39,10 +38,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 29b3331ba..a229cbe9b 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -5,11 +5,12 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -61,7 +62,7 @@ namespace MWClass } } - void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -76,7 +77,7 @@ namespace MWClass } boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; @@ -85,7 +86,7 @@ namespace MWClass { // TODO check for key std::cout << "Locked container" << std::endl; - environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, lockedSound, 1.0, 1.0); return boost::shared_ptr (new MWWorld::NullAction); } else @@ -100,7 +101,7 @@ namespace MWClass { // Trap activation goes here std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; - environment.mSoundManager->playSound3D (ptr, trapActivationSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, trapActivationSound, 1.0, 1.0); ptr.getCellRef().trap = ""; return boost::shared_ptr (new MWWorld::NullAction); } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 387714176..c371e8898 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -14,14 +14,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual MWWorld::ContainerStore& getContainerStore (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7270fd22b..b5a17b2b5 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -6,9 +6,10 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanager.hpp" +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" @@ -74,7 +75,7 @@ namespace MWClass actors.insertCreature(ptr); } - void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -87,14 +88,14 @@ namespace MWClass } } - void Creature::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + void Creature::enable (const MWWorld::Ptr& ptr) const { - environment.mMechanicsManager->addActor (ptr); + MWBase::Environment::get().getMechanicsManager()->addActor (ptr); } - void Creature::disable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + void Creature::disable (const MWWorld::Ptr& ptr) const { - environment.mMechanicsManager->removeActor (ptr); + MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); } std::string Creature::getName (const MWWorld::Ptr& ptr) const @@ -113,7 +114,7 @@ namespace MWClass } boost::shared_ptr Creature::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 8eb45e838..fa07f9625 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -20,12 +20,12 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + virtual void enable (const MWWorld::Ptr& ptr) const; ///< Enable reference; only does the non-rendering part - virtual void disable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + virtual void disable (const MWWorld::Ptr& ptr) const; ///< Enable reference; only does the non-rendering part virtual std::string getName (const MWWorld::Ptr& ptr) const; @@ -36,7 +36,7 @@ namespace MWClass ///< Return creature stats virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual MWWorld::ContainerStore& getContainerStore ( diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 9d6c6a78d..003beaa30 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -5,11 +5,12 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/player.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionteleport.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwrender/objects.hpp" @@ -34,7 +35,7 @@ namespace MWClass } } - void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -58,7 +59,7 @@ namespace MWClass } boost::shared_ptr Door::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -73,7 +74,7 @@ namespace MWClass // TODO check for key // TODO report failure to player (message, sound?). Look up behaviour of original MW. std::cout << "Locked!" << std::endl; - environment.mSoundManager->playSound3D (ptr, lockedSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, lockedSound, 1.0, 1.0); return boost::shared_ptr (new MWWorld::NullAction); } @@ -81,7 +82,7 @@ namespace MWClass { // Trap activation std::cout << "Activated trap: " << ptr.getCellRef().trap << std::endl; - environment.mSoundManager->playSound3D(ptr, trapActivationSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, trapActivationSound, 1.0, 1.0); ptr.getCellRef().trap = ""; return boost::shared_ptr (new MWWorld::NullAction); } @@ -89,11 +90,11 @@ namespace MWClass if (ref->ref.teleport) { // teleport door - if (environment.mWorld->getPlayer().getPlayer()==actor) + if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()==actor) { // the player is using the door // The reason this is not 3D is that it would get interrupted when you teleport - environment.mSoundManager->playSound(openSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound(openSound, 1.0, 1.0); return boost::shared_ptr ( new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest)); } @@ -110,7 +111,7 @@ namespace MWClass // TODO return action for rotating the door // This is a little pointless, but helps with testing - environment.mSoundManager->playSound3D (ptr, openSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, openSound, 1.0, 1.0); return boost::shared_ptr (new MWWorld::NullAction); } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index aecb4224c..4779ed174 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9707e79a8..79b1bb92f 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -52,9 +53,9 @@ namespace MWClass } boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -83,12 +84,12 @@ namespace MWClass registerClass (typeid (ESM::Ingredient).name(), instance); } - std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Ingredient::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Ingredient Up"); } - std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Ingredient::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Ingredient Down"); } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 2d7717672..d8190c8fc 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -30,10 +30,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f67dd4cf0..deb8c2567 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -5,10 +5,11 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwsound/soundmanager.hpp" @@ -39,7 +40,7 @@ namespace MWClass objects.insertLight (ptr, r, g, b, radius); } - void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -52,14 +53,14 @@ namespace MWClass } } - void Light::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + void Light::enable (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); if (!ref->base->sound.empty()) { - environment.mSoundManager->playSound3D (ptr, ref->base->sound, 1.0, 1.0, MWSound::Play_Loop); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, ref->base->sound, 1.0, 1.0, MWSound::Play_Loop); } } @@ -75,7 +76,7 @@ namespace MWClass } boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -83,7 +84,7 @@ namespace MWClass if (!(ref->base->data.flags & ESM::Light::Carry)) return boost::shared_ptr (new MWWorld::NullAction); - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -125,12 +126,12 @@ namespace MWClass registerClass (typeid (ESM::Light).name(), instance); } - std::string Light::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Light::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Misc Up"); } - std::string Light::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Light::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Misc Down"); } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index bde252c28..5d139cb8f 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -12,9 +12,9 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + virtual void enable (const MWWorld::Ptr& ptr) const; ///< Enable reference; only does the non-rendering part /// \attention This is not the same as the script instruction with the same name. References /// should only be enabled while in an active cell. @@ -24,7 +24,7 @@ namespace MWClass /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -39,10 +39,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 76bc3948f..d682538ea 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" @@ -32,7 +33,7 @@ namespace MWClass } } - void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -56,9 +57,9 @@ namespace MWClass } boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -96,12 +97,12 @@ namespace MWClass registerClass (typeid (ESM::Tool).name(), instance); } - std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Lockpick Up"); } - std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Lockpick::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Lockpick Down"); } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 1b56234af..042c726e4 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -34,10 +34,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 84099caaa..bcbf26870 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -54,9 +55,9 @@ namespace MWClass } boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -85,7 +86,7 @@ namespace MWClass registerClass (typeid (ESM::Miscellaneous).name(), instance); } - std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -97,7 +98,7 @@ namespace MWClass return std::string("Item Misc Up"); } - std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index fc002280c..bc05169c0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -30,10 +30,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c053ad130..aaa239d47 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -14,11 +14,12 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" +#include "../mwbase/environment.hpp" + namespace { const Ogre::Radian kOgrePi (Ogre::Math::PI); @@ -105,13 +106,13 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - - + + renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); - + } - void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { @@ -133,14 +134,14 @@ namespace MWClass } - void Npc::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + void Npc::enable (const MWWorld::Ptr& ptr) const { - environment.mMechanicsManager->addActor (ptr); + MWBase::Environment::get().getMechanicsManager()->addActor (ptr); } - void Npc::disable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const + void Npc::disable (const MWWorld::Ptr& ptr) const { - environment.mMechanicsManager->removeActor (ptr); + MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); } std::string Npc::getName (const MWWorld::Ptr& ptr) const @@ -166,7 +167,7 @@ namespace MWClass } boost::shared_ptr Npc::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f210eda5f..1ef77bd1b 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -17,12 +17,12 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + virtual void enable (const MWWorld::Ptr& ptr) const; ///< Enable reference; only does the non-rendering part - virtual void disable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const; + virtual void disable (const MWWorld::Ptr& ptr) const; ///< Enable reference; only does the non-rendering part virtual std::string getName (const MWWorld::Ptr& ptr) const; @@ -42,7 +42,7 @@ namespace MWClass ///< Return inventory store virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 642211df3..790b4d13e 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -54,9 +55,9 @@ namespace MWClass } boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -85,12 +86,12 @@ namespace MWClass registerClass (typeid (ESM::Potion).name(), instance); } - std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Potion::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Potion Up"); } - std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Potion::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Potion Down"); } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 7d3017937..f9137766b 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -30,10 +30,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 923c29ee6..bfb1d2951 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" @@ -32,7 +33,7 @@ namespace MWClass } } - void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -55,9 +56,9 @@ namespace MWClass return ref->base->name; } boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -95,12 +96,12 @@ namespace MWClass registerClass (typeid (ESM::Probe).name(), instance); } - std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Probe::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Probe Up"); } - std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Probe::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Probe Down"); } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 232b52364..543fa3f39 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -34,10 +34,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index d6433f5df..8bae71e19 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwrender/objects.hpp" @@ -31,7 +32,7 @@ namespace MWClass } } - void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -54,9 +55,9 @@ namespace MWClass } boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -85,12 +86,12 @@ namespace MWClass registerClass (typeid (ESM::Repair).name(), instance); } - std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Repair::getUpSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Repair Up"); } - std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Repair::getDownSoundId (const MWWorld::Ptr& ptr) const { return std::string("Item Repair Down"); } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 0a9d9c253..446ab325d 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual std::string getScript (const MWWorld::Ptr& ptr) const; @@ -30,10 +30,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 48750dd01..4a4136816 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -25,7 +25,7 @@ namespace MWClass } } - void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index a4b1d8c54..cd1626c19 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -12,7 +12,7 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 7790e6a80..22745f82d 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -5,9 +5,10 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwrender/objects.hpp" @@ -32,7 +33,7 @@ namespace MWClass } } - void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -55,9 +56,9 @@ namespace MWClass } boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const + const MWWorld::Ptr& actor) const { - environment.mSoundManager->playSound3D (ptr, getUpSoundId(ptr, environment), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -108,8 +109,7 @@ namespace MWClass return std::make_pair (slots, stack); } - int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr, - const MWWorld::Environment& environment) const + int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -154,7 +154,7 @@ namespace MWClass registerClass (typeid (ESM::Weapon).name(), instance); } - std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); @@ -200,7 +200,7 @@ namespace MWClass return std::string("Item Misc Up"); } - std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const + std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 505c45645..204d327ad 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -12,14 +12,14 @@ namespace MWClass virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering - virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. virtual boost::shared_ptr activate (const MWWorld::Ptr& ptr, - const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const; + const MWWorld::Ptr& actor) const; ///< Generate action for activation virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; @@ -35,8 +35,7 @@ namespace MWClass ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? - virtual int getEquipmentSkill (const MWWorld::Ptr& ptr, - const MWWorld::Environment& environment) const; + virtual int getEquipmentSkill (const MWWorld::Ptr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. @@ -45,10 +44,10 @@ namespace MWClass static void registerSelf(); - virtual std::string getUpSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; ///< Return the pick up sound Id - virtual std::string getDownSoundId (const MWWorld::Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id }; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 3188136b3..f753e936e 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -9,9 +9,9 @@ #include +#include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/player.hpp" @@ -181,7 +181,7 @@ namespace MWDialogue case 46://Same faction { - MWMechanics::NpcStats PCstats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); int sameFaction = 0; if(!NPCstats.mFactionRank.empty()) @@ -288,12 +288,12 @@ namespace MWDialogue if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || select.type==ESM::VT_Long) { - if (!checkGlobal (comp, toLower (name), select.i, *mEnvironment.mWorld)) + if (!checkGlobal (comp, toLower (name), select.i, *MWBase::Environment::get().getWorld())) return false; } else if (select.type==ESM::VT_Float) { - if (!checkGlobal (comp, toLower (name), select.f, *mEnvironment.mWorld)) + if (!checkGlobal (comp, toLower (name), select.f, *MWBase::Environment::get().getWorld())) return false; } else @@ -308,13 +308,13 @@ namespace MWDialogue select.type==ESM::VT_Long) { if (!checkLocal (comp, toLower (name), select.i, actor, - mEnvironment.mWorld->getStore())) + MWBase::Environment::get().getWorld()->getStore())) return false; } else if (select.type==ESM::VT_Float) { if (!checkLocal (comp, toLower (name), select.f, actor, - mEnvironment.mWorld->getStore())) + MWBase::Environment::get().getWorld()->getStore())) return false; } else @@ -326,7 +326,7 @@ namespace MWDialogue case '4'://journal if(select.type==ESM::VT_Int) { - if(!selectCompare(comp,mEnvironment.mJournal->getJournalIndex(toLower(name)),select.i)) return false; + if(!selectCompare(comp,MWBase::Environment::get().getJournal()->getJournalIndex(toLower(name)),select.i)) return false; } else throw std::runtime_error ( @@ -336,7 +336,7 @@ namespace MWDialogue case '5'://item { - MWWorld::Ptr player = mEnvironment.mWorld->getPlayer().getPlayer(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); int sum = 0; @@ -424,13 +424,13 @@ namespace MWDialogue select.type==ESM::VT_Long) { if (checkLocal (comp, toLower (name), select.i, actor, - mEnvironment.mWorld->getStore())) + MWBase::Environment::get().getWorld()->getStore())) return false; } else if (select.type==ESM::VT_Float) { if (checkLocal (comp, toLower (name), select.f, actor, - mEnvironment.mWorld->getStore())) + MWBase::Environment::get().getWorld()->getStore())) return false; } else @@ -500,7 +500,7 @@ namespace MWDialogue // TODO check player faction if(!info.pcFaction.empty()) { - MWMechanics::NpcStats stats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer()); + MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); std::map::iterator it = stats.mFactionRank.find(info.pcFaction); if(it!=stats.mFactionRank.end()) { @@ -528,7 +528,7 @@ namespace MWDialogue // check cell if (!info.cell.empty()) - if (mEnvironment.mWorld->getPlayer().getPlayer().getCell()->cell->name != info.cell) + if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->name != info.cell) return false; // TODO check DATAstruct @@ -540,8 +540,8 @@ namespace MWDialogue return true; } - DialogueManager::DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions) : - mEnvironment (environment),mCompilerContext (MWScript::CompilerContext::Type_Dialgoue, environment), + DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : + mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) { mChoice = -1; @@ -549,7 +549,7 @@ namespace MWDialogue mCompilerContext.setExtensions (&extensions); mDialogueMap.clear(); actorKnownTopics.clear(); - ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { mDialogueMap[toLower(it->first)] = it->second; @@ -592,8 +592,8 @@ namespace MWDialogue actorKnownTopics.clear(); //initialise the GUI - mEnvironment.mInputManager->setGuiMode(MWGui::GM_Dialogue); - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Dialogue); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->startDialogue(MWWorld::Class::get (actor).getName (actor)); //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI @@ -601,8 +601,8 @@ namespace MWDialogue //greeting bool greetingFound = false; - //ESMS::RecListT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; - ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + //ESMS::RecListT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; + ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { ESM::Dialogue ndialogue = it->second; @@ -650,7 +650,7 @@ namespace MWDialogue if (!actorScript.empty()) { // grab local variables from actor's script, if available. - locals = mEnvironment.mScriptManager->getLocals (actorScript); + locals = MWBase::Environment::get().getScriptManager()->getLocals (actorScript); } Compiler::ScriptParser parser(mErrorHandler,mCompilerContext, locals, false); @@ -683,7 +683,7 @@ namespace MWDialogue { try { - MWScript::InterpreterContext interpreterContext(mEnvironment,&mActor.getRefData().getLocals(),mActor); + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); Interpreter::Interpreter interpreter; MWScript::installOpcodes (interpreter); interpreter.run (&code[0], code.size(), interpreterContext); @@ -701,8 +701,8 @@ namespace MWDialogue int choice = mChoice; mChoice = -1; actorKnownTopics.clear(); - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); - ESMS::RecListCaseT::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list; + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { ESM::Dialogue ndialogue = it->second; @@ -747,7 +747,7 @@ namespace MWDialogue parseText(text); - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->addTitle(keyword); win->addText(iter->response); @@ -767,7 +767,7 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { - mEnvironment.mInputManager->setGuiMode(MWGui::GM_Game); + MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); } void DialogueManager::questionAnswered(std::string answere) @@ -790,7 +790,7 @@ namespace MWDialogue mChoiceMap.clear(); mChoice = -1; mIsInChoice = false; - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); std::string text = iter->response; parseText(text); win->addText(text); @@ -808,13 +808,13 @@ namespace MWDialogue void DialogueManager::printError(std::string error) { - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->addText(error); } void DialogueManager::askQuestion(std::string question, int choice) { - MWGui::DialogueWindow* win = mEnvironment.mWindowManager->getDialogueWindow(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); mChoiceMap[question] = choice; mIsInChoice = true; diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanager.hpp index d0380fa71..a3e37987d 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanager.hpp @@ -11,17 +11,10 @@ #include "../mwworld/ptr.hpp" #include -namespace MWWorld -{ - class Environment; -} - namespace MWDialogue { class DialogueManager { - MWWorld::Environment& mEnvironment; - bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const; bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const; @@ -39,7 +32,7 @@ namespace MWDialogue MWScript::CompilerContext mCompilerContext; std::ostream mErrorStream; Compiler::StreamErrorHandler mErrorHandler; - + bool compile (const std::string& cmd,std::vector& code); void executeScript(std::string script); @@ -55,7 +48,7 @@ namespace MWDialogue public: - DialogueManager (MWWorld::Environment& environment,const Compiler::Extensions& extensions); + DialogueManager (const Compiler::Extensions& extensions); void startDialogue (const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journal.cpp index 0715214eb..e0245406e 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journal.cpp @@ -1,7 +1,7 @@ #include "journal.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwgui/window_manager.hpp" #include "../mwgui/messagebox.hpp" @@ -23,31 +23,30 @@ namespace MWDialogue return iter->second; } - Journal::Journal (MWWorld::Environment& environment) - : mEnvironment (environment) + Journal::Journal() {} void Journal::addEntry (const std::string& id, int index) { StampedJournalEntry entry = - StampedJournalEntry::makeFromQuest (id, index, *mEnvironment.mWorld); + StampedJournalEntry::makeFromQuest (id, index, *MWBase::Environment::get().getWorld()); mJournal.push_back (entry); Quest& quest = getQuest (id); - quest.addEntry (entry, *mEnvironment.mWorld); // we are doing slicing on purpose here - + quest.addEntry (entry, *MWBase::Environment::get().getWorld()); // we are doing slicing on purpose here + std::vector empty; std::string notification = "Your Journal has been updated."; - mEnvironment.mWindowManager->messageBox (notification, empty); + MWBase::Environment::get().getWindowManager()->messageBox (notification, empty); } void Journal::setJournalIndex (const std::string& id, int index) { Quest& quest = getQuest (id); - quest.setIndex (index, *mEnvironment.mWorld); + quest.setIndex (index, *MWBase::Environment::get().getWorld()); } void Journal::addTopic (const std::string& topicId, const std::string& infoId) @@ -62,7 +61,7 @@ namespace MWDialogue iter = result.first; } - iter->second.addEntry (JournalEntry (topicId, infoId), *mEnvironment.mWorld); + iter->second.addEntry (JournalEntry (topicId, infoId), *MWBase::Environment::get().getWorld()); } int Journal::getJournalIndex (const std::string& id) const diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journal.hpp index ff1343945..62b9f4bed 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journal.hpp @@ -8,11 +8,6 @@ #include "journalentry.hpp" #include "quest.hpp" -namespace MWWorld -{ - struct Environment; -} - namespace MWDialogue { /// \brief The player's journal @@ -29,7 +24,6 @@ namespace MWDialogue private: - MWWorld::Environment& mEnvironment; TEntryContainer mJournal; TQuestContainer mQuests; TTopicContainer mTopics; @@ -38,7 +32,7 @@ namespace MWDialogue public: - Journal (MWWorld::Environment& environment); + Journal(); void addEntry (const std::string& id, int index); ///< Add a journal entry. diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index ce5e744cc..9a2375855 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -8,6 +8,8 @@ #include "dialogue.hpp" #include "mode.hpp" +#include "../mwbase/environment.hpp" + namespace { struct Step @@ -93,7 +95,7 @@ namespace using namespace MWGui; -CharacterCreation::CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment) +CharacterCreation::CharacterCreation(WindowManager* _wm) : mNameDialog(0) , mRaceDialog(0) , mDialogueWindow(0) @@ -105,7 +107,6 @@ CharacterCreation::CharacterCreation(WindowManager* _wm, MWWorld::Environment* _ , mBirthSignDialog(0) , mReviewDialog(0) , mWM(_wm) - , mEnvironment(_environment) { mCreationStage = CSE_NotStarted; } @@ -279,8 +280,8 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) { const std::string &classId = mPickClassDialog->getClassId(); if (!classId.empty()) - mEnvironment->mMechanicsManager->setPlayerClass(classId); - const ESM::Class *klass = mEnvironment->mWorld->getStore().classes.find(classId); + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); + const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().classes.find(classId); if (klass) { mPlayerClass = *klass; @@ -307,7 +308,7 @@ void CharacterCreation::onPickClassDialogBack() { const std::string classId = mPickClassDialog->getClassId(); if (!classId.empty()) - mEnvironment->mMechanicsManager->setPlayerClass(classId); + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); mWM->removeDialog(mPickClassDialog); } @@ -345,7 +346,7 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) { mPlayerName = mNameDialog->getTextInput(); mWM->setValue("name", mPlayerName); - mEnvironment->mMechanicsManager->setPlayerName(mPlayerName); + MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); mWM->removeDialog(mNameDialog); } @@ -366,7 +367,7 @@ void CharacterCreation::onRaceDialogBack() { mPlayerRaceId = mRaceDialog->getRaceId(); if (!mPlayerRaceId.empty()) - mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); mWM->removeDialog(mRaceDialog); } @@ -380,7 +381,7 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) mPlayerRaceId = mRaceDialog->getRaceId(); mWM->setValue("race", mPlayerRaceId); if (!mPlayerRaceId.empty()) - mEnvironment->mMechanicsManager->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); mWM->removeDialog(mRaceDialog); } @@ -402,7 +403,7 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) mPlayerBirthSignId = mBirthSignDialog->getBirthId(); mWM->setBirthSign(mPlayerBirthSignId); if (!mPlayerBirthSignId.empty()) - mEnvironment->mMechanicsManager->setPlayerBirthsign(mPlayerBirthSignId); + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); mWM->removeDialog(mBirthSignDialog); } @@ -419,7 +420,7 @@ void CharacterCreation::onBirthSignDialogBack() { if (mBirthSignDialog) { - mEnvironment->mMechanicsManager->setPlayerBirthsign(mBirthSignDialog->getBirthId()); + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); mWM->removeDialog(mBirthSignDialog); } @@ -450,7 +451,7 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) klass.data.skills[i][1] = majorSkills[i]; klass.data.skills[i][0] = minorSkills[i]; } - mEnvironment->mMechanicsManager->setPlayerClass(klass); + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; mWM->setPlayerClass(klass); @@ -592,7 +593,7 @@ void CharacterCreation::onGenerateClassBack() if (mGenerateClassResultDialog) mWM->removeDialog(mGenerateClassResultDialog); - mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass); + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); mWM->setGuiMode(GM_Class); } @@ -601,7 +602,7 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { if (mGenerateClassResultDialog) mWM->removeDialog(mGenerateClassResultDialog); - mEnvironment->mMechanicsManager->setPlayerClass(mGenerateClass); + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); if (mCreationStage == CSE_ReviewNext) mWM->setGuiMode(GM_Review); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index b01e754d9..222754cdc 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -30,7 +30,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(WindowManager* _wm, MWWorld::Environment* _environment); + CharacterCreation(WindowManager* _wm); ~CharacterCreation(); //Show a dialog @@ -56,7 +56,6 @@ namespace MWGui ReviewDialog* mReviewDialog; WindowManager* mWM; - MWWorld::Environment* mEnvironment; //Player data std::string mPlayerName; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index ac4f4a82a..8e15abddd 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -7,6 +7,8 @@ #include "../mwscript/extensions.hpp" +#include "../mwbase/environment.hpp" + namespace MWGui { class ConsoleInterpreterContext : public MWScript::InterpreterContext @@ -15,15 +17,14 @@ namespace MWGui public: - ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, - MWWorld::Ptr reference); + ConsoleInterpreterContext (Console& console, MWWorld::Ptr reference); virtual void report (const std::string& message); }; ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console, - MWWorld::Environment& environment, MWWorld::Ptr reference) - : MWScript::InterpreterContext (environment, + MWWorld::Ptr reference) + : MWScript::InterpreterContext ( reference.isEmpty() ? 0 : &reference.getRefData().getLocals(), reference), mConsole (console) {} @@ -88,7 +89,7 @@ namespace MWGui scanner.listKeywords (mNames); // identifier - const ESMS::ESMStore& store = mEnvironment.mWorld->getStore(); + const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); for (ESMS::RecListList::const_iterator iter (store.recLists.begin()); iter!=store.recLists.end(); ++iter) @@ -101,11 +102,9 @@ namespace MWGui } } - Console::Console(int w, int h, MWWorld::Environment& environment, - const Compiler::Extensions& extensions) + Console::Console(int w, int h, const Compiler::Extensions& extensions) : Layout("openmw_console_layout.xml"), - mCompilerContext (MWScript::CompilerContext::Type_Console, environment), - mEnvironment (environment) + mCompilerContext (MWScript::CompilerContext::Type_Console) { setCoord(10,10, w-10, h/2); @@ -139,7 +138,7 @@ namespace MWGui void Console::disable() { setVisible(false); - // Remove keyboard focus from the console input whenever the + // Remove keyboard focus from the console input whenever the // console is turned off MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL); } @@ -241,7 +240,7 @@ namespace MWGui { try { - ConsoleInterpreterContext interpreterContext (*this, mEnvironment, MWWorld::Ptr()); + ConsoleInterpreterContext interpreterContext (*this, MWWorld::Ptr()); Interpreter::Interpreter interpreter; MWScript::installOpcodes (interpreter); std::vector code; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index eaf4299be..6974d8333 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -23,7 +23,6 @@ namespace MWGui private: MWScript::CompilerContext mCompilerContext; - MWWorld::Environment& mEnvironment; std::vector mNames; bool compile (const std::string& cmd, Compiler::Output& output); @@ -51,7 +50,7 @@ namespace MWGui StringList::iterator current; std::string editString; - Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions); + Console(int w, int h, const Compiler::Extensions& extensions); void enable(); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index fc7a36382..2386cf9a3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -3,7 +3,7 @@ #include "window_manager.hpp" #include "widgets.hpp" #include "components/esm_store/store.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwdialogue/dialoguemanager.hpp" #include @@ -36,9 +36,8 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su } -DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment) - : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager), - mEnvironment(environment) +DialogueWindow::DialogueWindow(WindowManager& parWindowManager) + : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) { // Centre dialog center(); @@ -54,7 +53,7 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager,MWWorld::Environm /// \todo scrolling the dialogue history with the mouse wheel doesn't work using this solution getWidget(eventbox, "EventBox"); eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - + //Topics list getWidget(topicsList, "TopicsList"); topicsList->setScrollVisible(true); @@ -83,9 +82,9 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) if(color != "#B29154") { UString key = history->getColorTextAt(cursorPosition); - if(color == "#686EBA") mEnvironment.mDialogueManager->keywordSelected(lower_string(key)); + if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - if(color == "#572D21") mEnvironment.mDialogueManager->questionAnswered(key); + if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(key); } } @@ -100,7 +99,7 @@ void DialogueWindow::open() void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) { - mEnvironment.mDialogueManager->goodbyeSelected(); + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index) @@ -108,7 +107,7 @@ void DialogueWindow::onSelectTopic(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; std::string topic = _sender->getItemNameAt(_index); - mEnvironment.mDialogueManager->keywordSelected(lower_string(topic)); + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } void DialogueWindow::startDialogue(std::string npcName) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index b80a016cb..5b8439758 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -9,11 +9,6 @@ namespace MWGui class WindowManager; } -namespace MWWorld -{ - class Environment; -} - /* This file contains the dialouge window Layout is defined by resources/mygui/openmw_dialogue_window_layout.xml. @@ -28,7 +23,7 @@ namespace MWGui class DialogueWindow: public WindowBase { public: - DialogueWindow(WindowManager& parWindowManager,MWWorld::Environment& environment); + DialogueWindow(WindowManager& parWindowManager); void open(); @@ -65,8 +60,6 @@ namespace MWGui MyGUI::ProgressPtr pDispositionBar; MyGUI::EditPtr pDispositionText; std::map pTopicsText;// this map links keyword and "real" text. - - MWWorld::Environment& mEnvironment; }; } #endif diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 644bcbc04..e67eda777 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,7 +1,7 @@ #include "journalwindow.hpp" #include "window_manager.hpp" #include "../mwdialogue/journal.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "../mwsound/soundmanager.hpp" @@ -118,20 +118,20 @@ void MWGui::JournalWindow::open() { mPageNumber = 0; std::string journalOpenSound = "book open"; - mWindowManager.getEnvironment().mSoundManager->playSound (journalOpenSound, 1.0, 1.0); - if(mWindowManager.getEnvironment().mJournal->begin()!=mWindowManager.getEnvironment().mJournal->end()) + MWBase::Environment::get().getSoundManager()->playSound (journalOpenSound, 1.0, 1.0); + if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { book journal; journal.endLine = 0; - for(std::deque::const_iterator it = mWindowManager.getEnvironment().mJournal->begin();it!=mWindowManager.getEnvironment().mJournal->end();it++) + for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();it++) { - std::string a = it->getText(mWindowManager.getEnvironment().mWorld->getStore()); + std::string a = it->getText(MWBase::Environment::get().getWorld()->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::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); //std::list journal = formatText(a,10,20,1); bool left = true; for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();it++) @@ -155,7 +155,7 @@ void MWGui::JournalWindow::open() } else { - //std::cout << mWindowManager.getEnvironment().mJournal->begin()->getText(mWindowManager.getEnvironment().mWorld->getStore()); + //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); } } @@ -181,7 +181,7 @@ void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender) if(mPageNumber < int(leftPages.size())-1) { std::string nextSound = "book page2"; - mWindowManager.getEnvironment().mSoundManager->playSound (nextSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); mPageNumber = mPageNumber + 1; displayLeftText(leftPages[mPageNumber]); displayRightText(rightPages[mPageNumber]); @@ -193,7 +193,7 @@ void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender) if(mPageNumber > 0) { std::string prevSound = "book page"; - mWindowManager.getEnvironment().mSoundManager->playSound (prevSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); mPageNumber = mPageNumber - 1; displayLeftText(leftPages[mPageNumber]); displayRightText(rightPages[mPageNumber]); diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 34d62ba08..0792b0fcb 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -11,6 +11,8 @@ #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" +#include "../mwbase/environment.hpp" + #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" @@ -23,10 +25,9 @@ using namespace MWGui; -WindowManager::WindowManager(MWWorld::Environment& environment, +WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath) : mGuiManager(NULL) - , environment(environment) , hud(NULL) , map(NULL) , menu(NULL) @@ -76,15 +77,15 @@ WindowManager::WindowManager(MWWorld::Environment& environment, menu = new MainMenu(w,h); map = new MapWindow(*this); stats = new StatsWindow(*this); - console = new Console(w,h, environment, extensions); + console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); - dialogueWindow = new DialogueWindow(*this,environment); + dialogueWindow = new DialogueWindow(*this); // The HUD is always on hud->setVisible(true); - mCharGen = new CharacterCreation(this, &environment); + mCharGen = new CharacterCreation(this); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) @@ -143,7 +144,7 @@ void WindowManager::update() if (needModeChange) { needModeChange = false; - environment.mInputManager->setGuiMode(nextMode); + MWBase::Environment::get().getInputManager()->setGuiMode(nextMode); nextMode = GM_Game; } if (showFPSLevel > 0) @@ -154,11 +155,6 @@ void WindowManager::update() } } -MWWorld::Environment& WindowManager::getEnvironment() -{ - return environment; -} - void WindowManager::setNextMode(GuiMode newMode) { nextMode = newMode; @@ -167,7 +163,7 @@ void WindowManager::setNextMode(GuiMode newMode) void WindowManager::setGuiMode(GuiMode newMode) { - environment.mInputManager->setGuiMode(newMode); + MWBase::Environment::get().getInputManager()->setGuiMode(newMode); } void WindowManager::updateVisible() @@ -388,7 +384,7 @@ int WindowManager::readPressedButton () const std::string &WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { - const ESM::GameSetting *setting = environment.mWorld->getStore().gameSettings.search(id); + const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.search(id); if (setting && setting->type == ESM::VT_String) return setting->str; return default_; @@ -412,7 +408,7 @@ void WindowManager::onFrame (float frameDuration) const ESMS::ESMStore& WindowManager::getStore() const { - return environment.mWorld->getStore(); + return MWBase::Environment::get().getWorld()->getStore(); } void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 2b53560ba..6e446387e 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -34,7 +34,6 @@ namespace Compiler namespace MWWorld { - class Environment; class World; } @@ -83,7 +82,7 @@ namespace MWGui typedef std::vector FactionList; typedef std::vector SkillList; - WindowManager(MWWorld::Environment& environment, const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath); + WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string logpath); virtual ~WindowManager(); void setGuiMode(GuiMode newMode); @@ -95,8 +94,6 @@ namespace MWGui */ void update(); - MWWorld::Environment& getEnvironment(); - void setMode(GuiMode newMode) { if (newMode==GM_Inventory && allowed==GW_None) @@ -192,7 +189,6 @@ namespace MWGui private: OEngine::GUI::MyGUIManager *mGuiManager; - MWWorld::Environment& environment; HUD *hud; MapWindow *map; MainMenu *menu; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7d9f748d4..849ab8ea4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -19,10 +19,10 @@ namespace MWMechanics { if (!paused && ptr.getRefData().getHandle()!="player") MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( - MWWorld::Class::get (ptr).getNpcStats (ptr), mEnvironment); + MWWorld::Class::get (ptr).getNpcStats (ptr)); } - Actors::Actors (MWWorld::Environment& environment) : mEnvironment (environment), mDuration (0) {} + Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 7ff33b63b..ae93fb52e 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -12,16 +12,10 @@ namespace Ogre class Vector3; } -namespace MWWorld -{ - class Environment; -} - namespace MWMechanics { class Actors { - MWWorld::Environment& mEnvironment; std::set mActors; float mDuration; @@ -31,7 +25,7 @@ namespace MWMechanics public: - Actors (MWWorld::Environment& environment); + Actors(); void addActor (const MWWorld::Ptr& ptr); ///< Register an actor for stats management diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanager.cpp index f5711e78e..8bc408be6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.cpp @@ -5,8 +5,9 @@ #include "../mwgui/window_manager.hpp" +#include "../mwbase/environment.hpp" + #include "../mwworld/class.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -14,7 +15,7 @@ namespace MWMechanics { void MechanicsManager::buildPlayer() { - MWWorld::Ptr ptr = mEnvironment.mWorld->getPlayer().getPlayer(); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); MWMechanics::NpcStats& npcStats = MWWorld::Class::get (ptr).getNpcStats (ptr); @@ -33,10 +34,10 @@ namespace MWMechanics if (mRaceSelected) { const ESM::Race *race = - mEnvironment.mWorld->getStore().races.find ( - mEnvironment.mWorld->getPlayer().getRace()); + MWBase::Environment::get().getWorld()->getStore().races.find ( + MWBase::Environment::get().getWorld()->getPlayer().getRace()); - bool male = mEnvironment.mWorld->getPlayer().isMale(); + bool male = MWBase::Environment::get().getWorld()->getPlayer().isMale(); for (int i=0; i<8; ++i) { @@ -76,11 +77,11 @@ namespace MWMechanics } // birthsign - if (!mEnvironment.mWorld->getPlayer().getBirthsign().empty()) + if (!MWBase::Environment::get().getWorld()->getPlayer().getBirthsign().empty()) { const ESM::BirthSign *sign = - mEnvironment.mWorld->getStore().birthSigns.find ( - mEnvironment.mWorld->getPlayer().getBirthsign()); + MWBase::Environment::get().getWorld()->getStore().birthSigns.find ( + MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); for (std::vector::const_iterator iter (sign->powers.list.begin()); iter!=sign->powers.list.end(); ++iter) @@ -92,7 +93,7 @@ namespace MWMechanics // class if (mClassSelected) { - const ESM::Class& class_ = mEnvironment.mWorld->getPlayer().getClass(); + const ESM::Class& class_ = MWBase::Environment::get().getWorld()->getPlayer().getClass(); for (int i=0; i<2; ++i) { @@ -121,7 +122,7 @@ namespace MWMechanics } typedef ESMS::IndexListT::MapType ContainerType; - const ContainerType& skills = mEnvironment.mWorld->getStore().skills.list; + const ContainerType& skills = MWBase::Environment::get().getWorld()->getStore().skills.list; for (ContainerType::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) { @@ -164,7 +165,7 @@ namespace MWMechanics MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (creature).getCreatureStats (creature); - MagicEffects now = creatureStats.mSpells.getMagicEffects (mEnvironment); + MagicEffects now = creatureStats.mSpells.getMagicEffects(); /// \todo add effects from active spells and equipment @@ -175,9 +176,9 @@ namespace MWMechanics // TODO apply diff to other stats } - MechanicsManager::MechanicsManager (MWWorld::Environment& environment) - : mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false), - mRaceSelected (false), mActors (environment) + MechanicsManager::MechanicsManager() + : mUpdatePlayer (true), mClassSelected (false), + mRaceSelected (false) { buildPlayer(); } @@ -236,7 +237,7 @@ namespace MWMechanics { mWatchedCreature.mAttributes[i] = stats.mAttributes[i]; - mEnvironment.mWindowManager->setValue (attributeNames[i], stats.mAttributes[i]); + MWBase::Environment::get().getWindowManager()->setValue (attributeNames[i], stats.mAttributes[i]); } } @@ -246,7 +247,7 @@ namespace MWMechanics { mWatchedCreature.mDynamic[i] = stats.mDynamic[i]; - mEnvironment.mWindowManager->setValue (dynamicNames[i], stats.mDynamic[i]); + MWBase::Environment::get().getWindowManager()->setValue (dynamicNames[i], stats.mDynamic[i]); } } @@ -259,25 +260,25 @@ namespace MWMechanics { update = true; mWatchedNpc.mSkill[i] = npcStats.mSkill[i]; - mEnvironment.mWindowManager->setValue((ESM::Skill::SkillEnum)i, npcStats.mSkill[i]); + MWBase::Environment::get().getWindowManager()->setValue((ESM::Skill::SkillEnum)i, npcStats.mSkill[i]); } } if (update) - mEnvironment.mWindowManager->updateSkillArea(); + MWBase::Environment::get().getWindowManager()->updateSkillArea(); - mEnvironment.mWindowManager->setValue ("level", stats.mLevel); + MWBase::Environment::get().getWindowManager()->setValue ("level", stats.mLevel); } if (mUpdatePlayer) { // basic player profile; should not change anymore after the creation phase is finished. - mEnvironment.mWindowManager->setValue ("name", mEnvironment.mWorld->getPlayer().getName()); - mEnvironment.mWindowManager->setValue ("race", - mEnvironment.mWorld->getStore().races.find (mEnvironment.mWorld->getPlayer(). + MWBase::Environment::get().getWindowManager()->setValue ("name", MWBase::Environment::get().getWorld()->getPlayer().getName()); + MWBase::Environment::get().getWindowManager()->setValue ("race", + MWBase::Environment::get().getWorld()->getStore().races.find (MWBase::Environment::get().getWorld()->getPlayer(). getRace())->name); - mEnvironment.mWindowManager->setValue ("class", - mEnvironment.mWorld->getPlayer().getClass().name); + MWBase::Environment::get().getWindowManager()->setValue ("class", + MWBase::Environment::get().getWorld()->getPlayer().getClass().name); mUpdatePlayer = false; MWGui::WindowManager::SkillList majorSkills (5); @@ -285,11 +286,11 @@ namespace MWMechanics for (int i=0; i<5; ++i) { - minorSkills[i] = mEnvironment.mWorld->getPlayer().getClass().data.skills[i][0]; - majorSkills[i] = mEnvironment.mWorld->getPlayer().getClass().data.skills[i][1]; + minorSkills[i] = MWBase::Environment::get().getWorld()->getPlayer().getClass().data.skills[i][0]; + majorSkills[i] = MWBase::Environment::get().getWorld()->getPlayer().getClass().data.skills[i][1]; } - mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills); + MWBase::Environment::get().getWindowManager()->configureSkills (majorSkills, minorSkills); } mActors.update (movement, duration, paused); @@ -297,14 +298,14 @@ namespace MWMechanics void MechanicsManager::setPlayerName (const std::string& name) { - mEnvironment.mWorld->getPlayer().setName (name); + MWBase::Environment::get().getWorld()->getPlayer().setName (name); mUpdatePlayer = true; } void MechanicsManager::setPlayerRace (const std::string& race, bool male) { - mEnvironment.mWorld->getPlayer().setGender (male); - mEnvironment.mWorld->getPlayer().setRace (race); + MWBase::Environment::get().getWorld()->getPlayer().setGender (male); + MWBase::Environment::get().getWorld()->getPlayer().setRace (race); mRaceSelected = true; buildPlayer(); mUpdatePlayer = true; @@ -312,14 +313,14 @@ namespace MWMechanics void MechanicsManager::setPlayerBirthsign (const std::string& id) { - mEnvironment.mWorld->getPlayer().setBirthsign (id); + MWBase::Environment::get().getWorld()->getPlayer().setBirthsign (id); buildPlayer(); mUpdatePlayer = true; } void MechanicsManager::setPlayerClass (const std::string& id) { - mEnvironment.mWorld->getPlayer().setClass (*mEnvironment.mWorld->getStore().classes.find (id)); + MWBase::Environment::get().getWorld()->getPlayer().setClass (*MWBase::Environment::get().getWorld()->getStore().classes.find (id)); mClassSelected = true; buildPlayer(); mUpdatePlayer = true; @@ -327,7 +328,7 @@ namespace MWMechanics void MechanicsManager::setPlayerClass (const ESM::Class& class_) { - mEnvironment.mWorld->getPlayer().setClass (class_); + MWBase::Environment::get().getWorld()->getPlayer().setClass (class_); mClassSelected = true; buildPlayer(); mUpdatePlayer = true; diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanager.hpp index a121507ce..a26fb98cd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanager.hpp @@ -15,16 +15,10 @@ namespace Ogre class Vector3; } -namespace MWWorld -{ - class Environment; -} - namespace MWMechanics { class MechanicsManager { - MWWorld::Environment& mEnvironment; MWWorld::Ptr mWatched; CreatureStats mWatchedCreature; NpcStats mWatchedNpc; @@ -41,7 +35,7 @@ namespace MWMechanics public: - MechanicsManager (MWWorld::Environment& environment); + MechanicsManager (); void configureGUI(); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 916239a84..a53c75dc2 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -3,7 +3,8 @@ #include -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" #include "magiceffects.hpp" @@ -48,13 +49,13 @@ namespace MWMechanics mSelectedSpell.clear(); } - MagicEffects Spells::getMagicEffects (const MWWorld::Environment& environment) const + MagicEffects Spells::getMagicEffects() const { MagicEffects effects; for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { - const ESM::Spell *spell = environment.mWorld->getStore().spells.find (*iter); + const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().spells.find (*iter); if (spell->data.type==ESM::Spell::ST_Ability || spell->data.type==ESM::Spell::ST_Blight || spell->data.type==ESM::Spell::ST_Disease || spell->data.type==ESM::Spell::ST_Curse) diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index f7606c4ac..d90f5b502 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -9,11 +9,6 @@ namespace ESM struct Spell; } -namespace MWWorld -{ - struct Environment; -} - namespace MWMechanics { class MagicEffects; @@ -49,7 +44,7 @@ namespace MWMechanics ///< If the spell to be removed is the selected spell, the selected spell will be changed to /// no spell (empty string). - MagicEffects getMagicEffects (const MWWorld::Environment& environment) const; + MagicEffects getMagicEffects() const; ///< Return sum of magic effects resulting from abilities, blights, deseases and curses. void clear(); diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 5034e72b3..152cf3277 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -22,10 +22,10 @@ void Actors::setMwRoot(Ogre::SceneNode* root){ } void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ - insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend, inv); + insertBegin(ptr, true, true); + NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mRend, inv); - mAllActors[ptr] = anim; + mAllActors[ptr] = anim; } void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ Ogre::SceneNode* cellnode; @@ -68,7 +68,7 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ void Actors::insertCreature (const MWWorld::Ptr& ptr){ insertBegin(ptr, true, true); - CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mEnvironment, mRend); + CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr, mRend); //mAllActors.insert(std::pair(ptr,anim)); delete mAllActors[ptr]; mAllActors[ptr] = anim; diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 66c98c541..432bcc297 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -13,7 +13,6 @@ #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" -#include "../mwworld/environment.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" #include @@ -23,13 +22,12 @@ namespace MWRender{ OEngine::Render::OgreRenderer &mRend; std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; - MWWorld::Environment& mEnvironment; std::map mAllActors; public: - Actors(OEngine::Render::OgreRenderer& _rend, MWWorld::Environment& _env): mRend(_rend), mEnvironment(_env){} + Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5755418e2..fc6258208 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -4,10 +4,9 @@ namespace MWRender{ std::map Animation::mUniqueIDs; - Animation::Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend) + Animation::Animation(OEngine::Render::OgreRenderer& _rend) : insert(NULL) , mRend(_rend) - , mEnvironment(_env) , vecRotPos() , time(0.0f) , startTime(0.0f) @@ -428,7 +427,7 @@ namespace MWRender{ //base->_updateAnimation(); //base->_notifyMoved(); - + std::vector::iterator iter; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 98f0e7487..4ab60cff4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,7 +5,6 @@ #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" -#include "../mwworld/environment.hpp" #include #include #include @@ -21,16 +20,15 @@ struct PosAndRot{ }; class Animation{ - + protected: Ogre::SceneNode* insert; OEngine::Render::OgreRenderer &mRend; - MWWorld::Environment& mEnvironment; std::map vecRotPos; static std::map mUniqueIDs; - - - + + + float time; @@ -41,14 +39,14 @@ class Animation{ std::vectorrindexI; //Represents a translation index for each bone std::vectortindexI; - + //Only shapes with morphing data will use a shape number int shapeNumber; std::vector > shapeIndexI; //Ogre::SkeletonInstance* skel; std::vector* shapes; //All the NiTriShapeData for a creature - + std::vector* transformations; @@ -58,16 +56,16 @@ class Animation{ void handleAnimationTransforms(); bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); std::string getUniqueID(std::string mesh); - + public: - Animation(MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend); + Animation(OEngine::Render::OgreRenderer& _rend); virtual void runAnimation(float timepassed) = 0; void startScript(std::string groupname, int mode, int loops); void stopScript(); virtual ~Animation(); - + }; } #endif diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index e0eb5ccc2..9ca3ed731 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -10,7 +10,7 @@ namespace MWRender{ CreatureAnimation::~CreatureAnimation(){ } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend): Animation(_env,_rend){ +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend){ insert = ptr.getRefData().getBaseNode(); ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 2229eeec9..f50b7904b 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -7,20 +7,19 @@ #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: virtual ~CreatureAnimation(); - CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend); + CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend); virtual void runAnimation(float timepassed); - + }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index d42672179..be8afbae6 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -8,7 +8,7 @@ #include #include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/ptr.hpp" #include #include @@ -138,8 +138,8 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) return result; } -Debugging::Debugging(SceneNode *mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine) : - mMwRoot(mwRoot), mEnvironment(env), mEngine(engine), +Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) : + mMwRoot(mwRoot), mEngine(engine), mSceneMgr(mwRoot->getCreator()), mPathgridEnabled(false), mInteriorPathgridNode(NULL), mPathGridRoot(NULL), @@ -218,7 +218,7 @@ void Debugging::togglePathgrid() void Debugging::enableCellPathgrid(MWWorld::Ptr::CellStore *store) { - ESM::Pathgrid *pathgrid = mEnvironment.mWorld->getStore().pathgrids.search(*store->cell); + ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().pathgrids.search(*store->cell); if (!pathgrid) return; Vector3 cellPathGridPos(0, 0, 0); diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index ebf3884dc..e12c0647c 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -23,7 +23,6 @@ namespace Ogre namespace MWWorld { class World; - class Environment; } namespace MWRender @@ -34,7 +33,6 @@ namespace MWRender { OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; - MWWorld::Environment& mEnvironment; // Path grid stuff bool mPathgridEnabled; @@ -68,7 +66,7 @@ namespace MWRender Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* mwRoot, MWWorld::Environment &env, OEngine::Physic::PhysicEngine *engine); + Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine); ~Debugging(); bool toggleRenderMode (int mode); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 2cc233a01..ea8902443 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,7 +1,7 @@ #include "localmap.hpp" #include "renderingmanager.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "../mwgui/window_manager.hpp" #include "renderconst.hpp" @@ -12,12 +12,11 @@ using namespace MWRender; using namespace Ogre; -LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering, MWWorld::Environment* env) : +LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManager* rendering) : mInterior(false), mCellX(0), mCellY(0) { mRendering = rend; mRenderingManager = rendering; - mEnvironment = env; mCameraPosNode = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mCameraRotNode = mCameraPosNode->createChildSceneNode(); @@ -54,12 +53,12 @@ void LocalMap::saveTexture(const std::string& texname, const std::string& filena if (tex.isNull()) return; HardwarePixelBufferSharedPtr readbuffer = tex->getBuffer(); readbuffer->lock(HardwareBuffer::HBL_NORMAL ); - const PixelBox &readrefpb = readbuffer->getCurrentLock(); - uchar *readrefdata = static_cast(readrefpb.data); + const PixelBox &readrefpb = readbuffer->getCurrentLock(); + uchar *readrefdata = static_cast(readrefpb.data); Image img; img = img.loadDynamicImage (readrefdata, tex->getWidth(), - tex->getHeight(), tex->getFormat()); + tex->getHeight(), tex->getFormat()); img.save("./" + filename); readbuffer->unlock(); @@ -82,7 +81,7 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); Vector2 length = max-min; - + // divide into segments const int segsX = std::ceil( length.x / sSize ); const int segsY = std::ceil( length.y / sSize ); @@ -123,7 +122,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y); - const Vector2& north = mEnvironment->mWorld->getNorthVector(cell); + const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); Radian angle(std::atan2(-north.x, -north.y)); mAngle = angle.valueRadians(); mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0)); @@ -213,7 +212,7 @@ void LocalMap::render(const float x, const float y, texture, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, - xw*sMapResolution/sSize, yw*sMapResolution/sSize, + xw*sMapResolution/sSize, yw*sMapResolution/sSize, 0, PF_R8G8B8, TU_RENDERTARGET); @@ -236,7 +235,7 @@ void LocalMap::render(const float x, const float y, texture + "_fog", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, - xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize, + xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize, 0, PF_A8R8G8B8, TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); @@ -276,7 +275,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni return; } - // retrieve the x,y grid coordinates the player is in + // retrieve the x,y grid coordinates the player is in int x,y; Vector3 _pos(position.x, 0, position.z); Vector2 pos(_pos.x, _pos.z); @@ -303,7 +302,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni x = std::ceil((pos.x - min.x)/sSize)-1; y = std::ceil((pos.y - min.y)/sSize)-1; - mEnvironment->mWindowManager->setInteriorMapTexture(x,y); + MWBase::Environment::get().getWindowManager()->setInteriorMapTexture(x,y); } // convert from world coordinates to texture UV coordinates @@ -323,8 +322,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni texName = mInteriorName + "_" + coordStr(x,y); } - mEnvironment->mWindowManager->setPlayerPos(u, v); - mEnvironment->mWindowManager->setPlayerDir(playerdirection.x, -playerdirection.z); + MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); + MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); // explore radius (squared) const float sqrExploreRadius = 0.01 * sFogOfWarResolution*sFogOfWarResolution; diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 95685167c..9e03988f3 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -5,11 +5,6 @@ #include -namespace MWWorld -{ - class Environment; -} - namespace MWRender { class RenderingManager; @@ -20,7 +15,7 @@ namespace MWRender class LocalMap { public: - LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering, MWWorld::Environment* env); + LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); ~LocalMap(); /** @@ -61,7 +56,6 @@ namespace MWRender private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; - MWWorld::Environment* mEnvironment; // 1024*1024 pixels for a cell static const int sMapResolution = 1024; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 751a07548..94a746989 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,7 +2,7 @@ #include "../mwworld/world.hpp" #include "renderconst.hpp" - +#include "../mwbase/environment.hpp" using namespace Ogre; using namespace NifOgre; @@ -12,7 +12,7 @@ NpcAnimation::~NpcAnimation(){ } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_env,_rend), mStateID(-1), inv(_inv), timeToChange(0), +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_rend), mStateID(-1), inv(_inv), timeToChange(0), robe(inv.end()), helmet(inv.end()), shirt(inv.end()), cuirass(inv.end()), greaves(inv.end()), leftpauldron(inv.end()), rightpauldron(inv.end()), @@ -77,14 +77,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O std::string hairID = ref->base->hair; std::string headID = ref->base->head; headModel = "meshes\\" + - mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; + MWBase::Environment::get().getWorld()->getStore().bodyParts.find(headID)->model; hairModel = "meshes\\" + - mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model; + MWBase::Environment::get().getWorld()->getStore().bodyParts.find(hairID)->model; npcName = ref->base->name; //ESMStore::Races r = - const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().races.find(ref->base->race); bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); @@ -370,116 +370,116 @@ void NpcAnimation::updateParts(){ addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); } if(partpriorities[ESM::PRT_Neck] < 1){ - const ESM::BodyPart *neckPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck"); + const ESM::BodyPart *neckPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "neck"); if(neckPart) addOrReplaceIndividualPart(ESM::PRT_Neck, -1,1,"meshes\\" + neckPart->model); } if(partpriorities[ESM::PRT_Cuirass] < 1){ - const ESM::BodyPart *chestPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); + const ESM::BodyPart *chestPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "chest"); if(chestPart) addOrReplaceIndividualPart(ESM::PRT_Cuirass, -1,1,"meshes\\" + chestPart->model); } if(partpriorities[ESM::PRT_Groin] < 1){ - const ESM::BodyPart *groinPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin"); + const ESM::BodyPart *groinPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "groin"); if(groinPart) addOrReplaceIndividualPart(ESM::PRT_Groin, -1,1,"meshes\\" + groinPart->model); } if(partpriorities[ESM::PRT_RHand] < 1){ - const ESM::BodyPart *handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); + const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); if(!handPart) - handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands"); + handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); if(handPart) addOrReplaceIndividualPart(ESM::PRT_RHand, -1,1,"meshes\\" + handPart->model); } if(partpriorities[ESM::PRT_LHand] < 1){ - const ESM::BodyPart *handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); + const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); if(!handPart) - handPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands"); + handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); if(handPart) addOrReplaceIndividualPart(ESM::PRT_LHand, -1,1,"meshes\\" + handPart->model); } if(partpriorities[ESM::PRT_RWrist] < 1){ - const ESM::BodyPart *wristPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); + const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); if(wristPart) addOrReplaceIndividualPart(ESM::PRT_RWrist, -1,1,"meshes\\" + wristPart->model); } if(partpriorities[ESM::PRT_LWrist] < 1){ - const ESM::BodyPart *wristPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); + const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); if(wristPart) addOrReplaceIndividualPart(ESM::PRT_LWrist, -1,1,"meshes\\" + wristPart->model); } if(partpriorities[ESM::PRT_RForearm] < 1){ - const ESM::BodyPart *forearmPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); + const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); if(bodyRaceID == "b_n_argonian_f_") - forearmPart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); + forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); if(forearmPart) addOrReplaceIndividualPart(ESM::PRT_RForearm, -1,1,"meshes\\" + forearmPart->model); } if(partpriorities[ESM::PRT_LForearm] < 1){ - const ESM::BodyPart *forearmPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); + const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); if(bodyRaceID == "b_n_argonian_f_") - forearmPart = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); + forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); if(forearmPart) addOrReplaceIndividualPart(ESM::PRT_LForearm, -1,1,"meshes\\" + forearmPart->model); } if(partpriorities[ESM::PRT_RUpperarm] < 1){ - const ESM::BodyPart *armPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); + const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); if(armPart) addOrReplaceIndividualPart(ESM::PRT_RUpperarm, -1,1,"meshes\\" + armPart->model); } if(partpriorities[ESM::PRT_LUpperarm] < 1){ - const ESM::BodyPart *armPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); + const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); if(armPart) addOrReplaceIndividualPart(ESM::PRT_LUpperarm, -1,1,"meshes\\" + armPart->model); } if(partpriorities[ESM::PRT_RFoot] < 1){ - const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); + const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); if(isBeast && !footPart) - footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); + footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); if(footPart) addOrReplaceIndividualPart(ESM::PRT_RFoot, -1,1,"meshes\\" + footPart->model); } if(partpriorities[ESM::PRT_LFoot] < 1){ - const ESM::BodyPart *footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot"); + const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); if(isBeast && !footPart) - footPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet"); + footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); if(footPart) addOrReplaceIndividualPart(ESM::PRT_LFoot, -1,1,"meshes\\" + footPart->model); } if(partpriorities[ESM::PRT_RAnkle] < 1){ - const ESM::BodyPart *anklePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle"); + const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); if(anklePart) addOrReplaceIndividualPart(ESM::PRT_RAnkle, -1,1,"meshes\\" + anklePart->model); } if(partpriorities[ESM::PRT_LAnkle] < 1){ - const ESM::BodyPart *anklePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle"); + const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); if(anklePart) addOrReplaceIndividualPart(ESM::PRT_LAnkle, -1,1,"meshes\\" + anklePart->model); } if(partpriorities[ESM::PRT_RKnee] < 1){ - const ESM::BodyPart *kneePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee"); + const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); if(kneePart) addOrReplaceIndividualPart(ESM::PRT_RKnee, -1,1,"meshes\\" + kneePart->model); } if(partpriorities[ESM::PRT_LKnee] < 1){ - const ESM::BodyPart *kneePart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee"); + const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); if(kneePart) addOrReplaceIndividualPart(ESM::PRT_LKnee, -1,1,"meshes\\" + kneePart->model); } if(partpriorities[ESM::PRT_RLeg] < 1){ - const ESM::BodyPart *legPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); + const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); if(legPart) addOrReplaceIndividualPart(ESM::PRT_RLeg, -1,1,"meshes\\" + legPart->model); } if(partpriorities[ESM::PRT_LLeg] < 1){ - const ESM::BodyPart *legPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg"); + const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); if(legPart) addOrReplaceIndividualPart(ESM::PRT_LLeg, -1,1,"meshes\\" + legPart->model); } if(partpriorities[ESM::PRT_Tail] < 1){ - const ESM::BodyPart *tailPart = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail"); + const ESM::BodyPart *tailPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "tail"); if(tailPart) addOrReplaceIndividualPart(ESM::PRT_Tail, -1,1,"meshes\\" + tailPart->model); } @@ -848,9 +848,9 @@ void NpcAnimation::removeIndividualPart(int type){ const ESM::BodyPart *bodypart = 0; if(isFemale) - bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.female); + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.female); if(!bodypart) - bodypart = mEnvironment.mWorld->getStore().bodyParts.search (part.male); + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.male); if(bodypart){ addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 352b54bec..a37becc26 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -10,7 +10,6 @@ #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/environment.hpp" #include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwclass/npc.hpp" @@ -36,8 +35,8 @@ private: int partpriorities[27]; std::pair*> zero; - - + + //Bounded Parts Ogre::Entity* lclavicle; Ogre::Entity* rclavicle; @@ -59,7 +58,7 @@ private: Ogre::Entity* rfoot; Ogre::Entity* hair; Ogre::Entity* head; - + Ogre::SceneNode* insert; bool isBeast; bool isFemale; @@ -80,9 +79,9 @@ private: MWWorld::ContainerStoreIterator leftglove; MWWorld::ContainerStoreIterator rightglove; MWWorld::ContainerStoreIterator skirtiter; - + public: - NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); + NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); virtual ~NpcAnimation(); Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); std::pair*> insertFreePart(const std::string &mesh, const std::string suffix); @@ -91,12 +90,12 @@ private: void updateParts(); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); - + bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); - + }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c1462807f..266fbfb62 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -24,8 +24,8 @@ using namespace Ogre; namespace MWRender { -RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment) - :mRendering(_rend), mObjects(mRendering), mActors(mRendering, environment), mAmbientMode(0), mSunEnabled(0) +RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine) + :mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0) { mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); @@ -93,19 +93,18 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mShadows = new Shadows(&mRendering); mShaderHelper = new ShaderHelper(this); - mTerrainManager = new TerrainManager(mRendering.getScene(), this, - environment); + mTerrainManager = new TerrainManager(mRendering.getScene(), this); //mSkyManager = 0; - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); + mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mSun = 0; - mDebugging = new Debugging(mMwRoot, environment, engine); - mLocalMap = new MWRender::LocalMap(&mRendering, this, &environment); + mDebugging = new Debugging(mMwRoot, engine); + mLocalMap = new MWRender::LocalMap(&mRendering, this); } RenderingManager::~RenderingManager () diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a563d78c6..c4134eede 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -57,7 +57,7 @@ class RenderingManager: private RenderingInterface { virtual MWRender::Actors& getActors(); public: - RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment); + RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine); virtual ~RenderingManager(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 859da2dc1..da2e7446a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -10,7 +10,7 @@ #include -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwworld/world.hpp" #include "renderconst.hpp" #include "renderingmanager.hpp" @@ -271,10 +271,10 @@ void Moon::setPhase(const Moon::Phase& phase) { // Colour texture 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"; @@ -283,9 +283,9 @@ void Moon::setPhase(const Moon::Phase& phase) 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; @@ -365,9 +365,8 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera, MWWorld::Environment* env) - : mEnvironment(env) - , mHour(0.0f) +SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) + : mHour(0.0f) , mDay(0) , mMonth(0) , mSun(NULL) @@ -713,7 +712,7 @@ void SkyManager::update(float duration) if (!mEnabled) return; // UV Scroll the clouds - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", mEnvironment->mWorld->getTimeScaleFactor()/30.f); + mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); @@ -752,7 +751,7 @@ void SkyManager::update(float duration) mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days - mAtmosphereNight->roll(Degree(mEnvironment->mWorld->getTimeScaleFactor()*duration*360 / (3600*96.f))); + mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } void SkyManager::enable() diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 64d5c16a0..da89d0eb0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -59,8 +59,8 @@ namespace MWRender Ogre::MaterialPtr mMaterial; Ogre::BillboardSet* mBBSet; }; - - + + /* * The moons need a seperate class because of their shader (which allows them to be partially transparent) */ @@ -104,11 +104,11 @@ namespace MWRender Type mType; Phase mPhase; }; - + class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera, MWWorld::Environment* env); + SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); ~SkyManager(); void update(float duration); @@ -176,7 +176,6 @@ namespace MWRender private: bool mCreated; - MWWorld::Environment* mEnvironment; float mHour; int mDay; int mMonth; diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index f9b43655b..90d853f75 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -4,6 +4,8 @@ #include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" + #include "terrainmaterial.hpp" #include "terrain.hpp" #include "renderconst.hpp" @@ -17,8 +19,8 @@ namespace MWRender //---------------------------------------------------------------------------------------------- - TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& evn) : - mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) + TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : + mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) { TerrainMaterialGeneratorPtr matGen; @@ -107,7 +109,7 @@ namespace MWRender const int cellX = store->cell->getGridX(); const int cellY = store->cell->getGridY(); - ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY); + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cellX, cellY); if ( land != NULL ) { if (!land->dataLoaded) @@ -268,7 +270,7 @@ namespace MWRender { //NB: All vtex ids are +1 compared to the ltex ids - assert( (int)mEnvironment.mWorld->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && + assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && "LAND.VTEX must be within the bounds of the LTEX array"); std::string texture; @@ -278,7 +280,7 @@ namespace MWRender } else { - texture = mEnvironment.mWorld->getStore().landTexts.search(ltexIndex-1)->texture; + texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1)->texture; //TODO this is needed due to MWs messed up texture handling texture = texture.substr(0, texture.rfind(".")) + ".dds"; } @@ -434,7 +436,7 @@ namespace MWRender } - ESM::Land* land = mEnvironment.mWorld->getStore().lands.search(cellX, cellY); + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cellX, cellY); if ( land != NULL ) { if (!land->dataLoaded) diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index dc4a2388c..c4ff053a6 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -24,7 +24,7 @@ namespace MWRender{ */ class TerrainManager{ public: - TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& env); + TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend); virtual ~TerrainManager(); void setDiffuse(const Ogre::ColourValue& diffuse); @@ -36,7 +36,6 @@ namespace MWRender{ Ogre::TerrainGlobalOptions mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; - const MWWorld::Environment& mEnvironment; RenderingManager* mRendering; Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 184be83db..864a2bf1d 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -27,10 +27,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getWorld().skipAnimation (ptr); + MWBase::Environment::get().getWorld()->skipAnimation (ptr); } }; @@ -43,9 +40,6 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - InterpreterContext& context = - static_cast (runtime.getContext()); - std::string group = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -60,7 +54,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - context.getWorld().playAnimationGroup (ptr, group, mode, 1); + MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, 1); } }; @@ -73,9 +67,6 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - InterpreterContext& context = - static_cast (runtime.getContext()); - std::string group = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -96,7 +87,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - context.getWorld().playAnimationGroup (ptr, group, mode, loops); + MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops); } }; diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index d69c42ab3..a5db5fd5f 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -22,10 +24,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - - runtime.push (context.getWorld().hasCellChanged() ? 1 : 0); + runtime.push (MWBase::Environment::get().getWorld()->hasCellChanged() ? 1 : 0); } }; @@ -35,9 +34,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - std::string cell = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -45,16 +41,16 @@ namespace MWScript pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; pos.pos[2] = 0; - if (const ESM::Cell *exterior = context.getWorld().getExterior (cell)) + if (const ESM::Cell *exterior = MWBase::Environment::get().getWorld()->getExterior (cell)) { - context.getWorld().indexToPosition (exterior->data.gridX, exterior->data.gridY, + MWBase::Environment::get().getWorld()->indexToPosition (exterior->data.gridX, exterior->data.gridY, pos.pos[0], pos.pos[1], true); - context.getWorld().changeToExteriorCell (pos); + MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); } else { pos.pos[0] = pos.pos[1] = 0; - context.getWorld().changeToInteriorCell (cell, pos); + MWBase::Environment::get().getWorld()->changeToInteriorCell (cell, pos); } } }; @@ -65,9 +61,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - Interpreter::Type_Integer x = runtime[0].mInteger; runtime.pop(); @@ -76,12 +69,12 @@ namespace MWScript ESM::Position pos; - context.getWorld().indexToPosition (x, y, pos.pos[0], pos.pos[1], true); + MWBase::Environment::get().getWorld()->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - context.getWorld().changeToExteriorCell (pos); + MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); } }; @@ -91,11 +84,8 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool interior = - context.getWorld().getPlayer().getPlayer().getCell()->cell->data.flags & + MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->data.flags & ESM::Cell::Interior; runtime.push (interior ? 1 : 0); @@ -108,20 +98,17 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - const ESM::Cell *cell = context.getWorld().getPlayer().getPlayer().getCell()->cell; + const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell; std::string current = cell->name; if (!(cell->data.flags & ESM::Cell::Interior) && current.empty()) { const ESM::Region *region = - context.getWorld().getStore().regions.find (cell->region); + MWBase::Environment::get().getWorld()->getStore().regions.find (cell->region); current = region->name; } @@ -139,10 +126,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - - MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell(); + MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); runtime.push (cell->mWaterLevel); } }; @@ -153,18 +137,15 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - Interpreter::Type_Float level = runtime[0].mFloat; - MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell(); + MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); if (!(cell->cell->data.flags & ESM::Cell::Interior)) throw std::runtime_error("Can't set water level in exterior cell"); cell->mWaterLevel = level; - context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel); + MWBase::Environment::get().getWorld()->setWaterHeight(cell->mWaterLevel); } }; @@ -174,18 +155,15 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - Interpreter::Type_Float level = runtime[0].mFloat; - MWWorld::Ptr::CellStore *cell = context.getWorld().getPlayer().getPlayer().getCell(); + MWWorld::Ptr::CellStore *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); if (!(cell->cell->data.flags & ESM::Cell::Interior)) throw std::runtime_error("Can't set water level in exterior cell"); - + cell->mWaterLevel +=level; - context.getEnvironment().mWorld->setWaterHeight(cell->mWaterLevel); + MWBase::Environment::get().getWorld()->setWaterHeight(cell->mWaterLevel); } }; diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 15cc599a7..078d0da5e 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,48 +1,48 @@ #include "compilercontext.hpp" -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" namespace MWScript { - CompilerContext::CompilerContext (Type type, const MWWorld::Environment& environment) - : mType (type), mEnvironment (environment) + CompilerContext::CompilerContext (Type type) + : mType (type) {} bool CompilerContext::canDeclareLocals() const { return mType==Type_Full; - } - + } + char CompilerContext::getGlobalType (const std::string& name) const { - return mEnvironment.mWorld->getGlobalVariableType (name); - } - + return MWBase::Environment::get().getWorld()->getGlobalVariableType (name); + } + bool CompilerContext::isId (const std::string& name) const { return - mEnvironment.mWorld->getStore().activators.search (name) || - mEnvironment.mWorld->getStore().potions.search (name) || - mEnvironment.mWorld->getStore().appas.search (name) || - mEnvironment.mWorld->getStore().armors.search (name) || - mEnvironment.mWorld->getStore().books.search (name) || - mEnvironment.mWorld->getStore().clothes.search (name) || - mEnvironment.mWorld->getStore().containers.search (name) || - mEnvironment.mWorld->getStore().creatures.search (name) || - mEnvironment.mWorld->getStore().doors.search (name) || - mEnvironment.mWorld->getStore().ingreds.search (name) || - mEnvironment.mWorld->getStore().creatureLists.search (name) || - mEnvironment.mWorld->getStore().itemLists.search (name) || - mEnvironment.mWorld->getStore().lights.search (name) || - mEnvironment.mWorld->getStore().lockpicks.search (name) || - mEnvironment.mWorld->getStore().miscItems.search (name) || - mEnvironment.mWorld->getStore().npcs.search (name) || - mEnvironment.mWorld->getStore().probes.search (name) || - mEnvironment.mWorld->getStore().repairs.search (name) || - mEnvironment.mWorld->getStore().statics.search (name) || - mEnvironment.mWorld->getStore().weapons.search (name); + MWBase::Environment::get().getWorld()->getStore().activators.search (name) || + MWBase::Environment::get().getWorld()->getStore().potions.search (name) || + MWBase::Environment::get().getWorld()->getStore().appas.search (name) || + MWBase::Environment::get().getWorld()->getStore().armors.search (name) || + MWBase::Environment::get().getWorld()->getStore().books.search (name) || + MWBase::Environment::get().getWorld()->getStore().clothes.search (name) || + MWBase::Environment::get().getWorld()->getStore().containers.search (name) || + MWBase::Environment::get().getWorld()->getStore().creatures.search (name) || + MWBase::Environment::get().getWorld()->getStore().doors.search (name) || + MWBase::Environment::get().getWorld()->getStore().ingreds.search (name) || + MWBase::Environment::get().getWorld()->getStore().creatureLists.search (name) || + MWBase::Environment::get().getWorld()->getStore().itemLists.search (name) || + MWBase::Environment::get().getWorld()->getStore().lights.search (name) || + MWBase::Environment::get().getWorld()->getStore().lockpicks.search (name) || + MWBase::Environment::get().getWorld()->getStore().miscItems.search (name) || + MWBase::Environment::get().getWorld()->getStore().npcs.search (name) || + MWBase::Environment::get().getWorld()->getStore().probes.search (name) || + MWBase::Environment::get().getWorld()->getStore().repairs.search (name) || + MWBase::Environment::get().getWorld()->getStore().statics.search (name) || + MWBase::Environment::get().getWorld()->getStore().weapons.search (name); } } - diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 7a3411bba..32b2f1881 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -3,44 +3,36 @@ #include -namespace MWWorld -{ - class Environment; -} - namespace MWScript { class CompilerContext : public Compiler::Context { public: - + enum Type { Type_Full, // global, local, targetted Type_Dialgoue, Type_Console }; - + private: - + Type mType; - const MWWorld::Environment& mEnvironment; - + public: - - CompilerContext (Type type, const MWWorld::Environment& environment); - + + CompilerContext (Type type); + /// Is the compiler allowed to declare local variables? - virtual bool canDeclareLocals() const; - - /// 'l: long, 's': short, 'f': float, ' ': does not exist. + virtual bool canDeclareLocals() const; + + /// 'l: long, 's': short, 'f': float, ' ': does not exist. virtual char getGlobalType (const std::string& name) const; virtual bool isId (const std::string& name) const; - ///< Does \a name match an ID, that can be referenced? + ///< Does \a name match an ID, that can be referenced? }; } #endif - - diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index a0aba5db9..3e8658bf8 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -9,6 +9,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -29,9 +31,6 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -41,7 +40,7 @@ namespace MWScript if (count<0) throw std::runtime_error ("second argument for AddItem must be non-negative"); - MWWorld::ManualRef ref (context.getWorld().getStore(), item); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 384e13e45..363a09b6b 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/player.hpp" #include "interpretercontext.hpp" @@ -46,7 +48,7 @@ namespace MWScript InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = context.getWorld().toggleCollisionMode(); + bool enabled = MWBase::Environment::get().getWorld()->toggleCollisionMode(); context.report (enabled ? "Collision -> On" : "Collision -> Off"); } diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index fec539d3e..b99d55999 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -23,16 +23,13 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string quest = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - context.getEnvironment().mJournal->addEntry (quest, index); + MWBase::Environment::get().getJournal()->addEntry (quest, index); } }; @@ -42,16 +39,13 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string quest = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Integer index = runtime[0].mInteger; runtime.pop(); - context.getEnvironment().mJournal->setJournalIndex (quest, index); + MWBase::Environment::get().getJournal()->setJournalIndex (quest, index); } }; @@ -61,13 +55,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string quest = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - int index = context.getEnvironment().mJournal->getJournalIndex (quest); + int index = MWBase::Environment::get().getJournal()->getJournalIndex (quest); runtime.push (index); @@ -80,13 +71,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string topic = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getEnvironment().mDialogueManager->addTopic(topic); + MWBase::Environment::get().getDialogueManager()->addTopic(topic); } }; @@ -96,9 +84,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - MWDialogue::DialogueManager* dialogue = context.getEnvironment().mDialogueManager; + MWDialogue::DialogueManager* dialogue = MWBase::Environment::get().getDialogueManager(); while(arg0>0) { std::string question = runtime.getStringLiteral (runtime[0].mInteger); @@ -124,9 +110,8 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - context.getEnvironment().mDialogueManager->startDialogue (ptr); + + MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); } }; diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 14930b828..eb96ba5e2 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -12,9 +12,9 @@ namespace MWScript : mStore (store), mScriptManager (scriptManager) { addScript ("Main"); - - for (ESMS::RecListT::MapType::const_iterator iter - (store.startScripts.list.begin()); + + for (ESMS::RecListT::MapType::const_iterator iter + (store.startScripts.list.begin()); iter != store.startScripts.list.end(); ++iter) addScript (iter->second.script); } @@ -23,15 +23,15 @@ namespace MWScript { if (mScripts.find (name)==mScripts.end()) if (const ESM::Script *script = mStore.scripts.find (name)) - { + { Locals locals; - + locals.configure (*script); - mScripts.insert (std::make_pair (name, std::make_pair (true, locals))); + mScripts.insert (std::make_pair (name, std::make_pair (true, locals))); } } - + void GlobalScripts::removeScript (const std::string& name) { std::map >::iterator iter = mScripts.find (name); @@ -39,31 +39,30 @@ namespace MWScript if (iter!=mScripts.end()) iter->second.first = false; } - + bool GlobalScripts::isRunning (const std::string& name) const { std::map >::const_iterator iter = mScripts.find (name); - + if (iter==mScripts.end()) return false; - + return iter->second.first; } - - void GlobalScripts::run (MWWorld::Environment& environment) + + void GlobalScripts::run() { for (std::map >::iterator iter (mScripts.begin()); iter!=mScripts.end(); ++iter) { if (iter->second.first) { - MWScript::InterpreterContext interpreterContext (environment, + MWScript::InterpreterContext interpreterContext ( &iter->second.second, MWWorld::Ptr()); - mScriptManager.run (iter->first, interpreterContext); + mScriptManager.run (iter->first, interpreterContext); } } } } - diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 741968fcd..3d62e4d7a 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -11,11 +11,6 @@ namespace ESMS struct ESMStore; } -namespace MWWorld -{ - class Environment; -} - namespace MWScript { class ScriptManager; @@ -25,21 +20,20 @@ namespace MWScript const ESMS::ESMStore& mStore; ScriptManager& mScriptManager; std::map > mScripts; // running, local variables - + public: - + GlobalScripts (const ESMS::ESMStore& store, ScriptManager& scriptManager); - + void addScript (const std::string& name); - + void removeScript (const std::string& name); - + bool isRunning (const std::string& name) const; - - void run (MWWorld::Environment& environment); + + void run(); ///< run all active global scripts }; } #endif - diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 426378efc..a37595ea8 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwgui/window_manager.hpp" #include "../mwinput/inputmanager.hpp" @@ -26,10 +28,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getWindowManager().allow (mWindow); + MWBase::Environment::get().getWindowManager()->allow (mWindow); } }; @@ -45,10 +44,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getInputManager().setGuiMode(mDialogue); + MWBase::Environment::get().getInputManager()->setGuiMode(mDialogue); } }; @@ -63,7 +59,7 @@ namespace MWScript MWWorld::Ptr ptr = context.getReference(); - runtime.push (context.getWindowManager().readPressedButton()); + runtime.push (MWBase::Environment::get().getWindowManager()->readPressedButton()); } }; @@ -73,10 +69,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getEnvironment().mWindowManager->toggleFogOfWar(); + MWBase::Environment::get().getWindowManager()->toggleFogOfWar(); } }; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index acd1d957d..a369486fa 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -7,6 +7,8 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" #include "../mwgui/window_manager.hpp" @@ -24,7 +26,7 @@ namespace MWScript { if (!id.empty()) { - return mEnvironment.mWorld->getPtr (id, activeOnly); + return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); } else { @@ -40,7 +42,7 @@ namespace MWScript { if (!id.empty()) { - return mEnvironment.mWorld->getPtr (id, activeOnly); + return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly); } else { @@ -51,9 +53,9 @@ namespace MWScript } } - InterpreterContext::InterpreterContext (MWWorld::Environment& environment, + InterpreterContext::InterpreterContext ( MWScript::Locals *locals, MWWorld::Ptr reference) - : mEnvironment (environment), mLocals (locals), mReference (reference), + : mLocals (locals), mReference (reference), mActivationHandled (false) {} @@ -108,7 +110,7 @@ namespace MWScript void InterpreterContext::messageBox (const std::string& message, const std::vector& buttons) { - mEnvironment.mWindowManager->messageBox (message, buttons); + MWBase::Environment::get().getWindowManager()->messageBox (message, buttons); } void InterpreterContext::report (const std::string& message) @@ -118,74 +120,74 @@ namespace MWScript bool InterpreterContext::menuMode() { - return mEnvironment.mWindowManager->isGuiMode(); + return MWBase::Environment::get().getWindowManager()->isGuiMode(); } int InterpreterContext::getGlobalShort (const std::string& name) const { - return mEnvironment.mWorld->getGlobalVariable (name).mShort; + return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort; } int InterpreterContext::getGlobalLong (const std::string& name) const { // a global long is internally a float. - return mEnvironment.mWorld->getGlobalVariable (name).mLong; + return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong; } float InterpreterContext::getGlobalFloat (const std::string& name) const { - return mEnvironment.mWorld->getGlobalVariable (name).mFloat; + return MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat; } void InterpreterContext::setGlobalShort (const std::string& name, int value) { if (name=="gamehour") - mEnvironment.mWorld->setHour (value); + MWBase::Environment::get().getWorld()->setHour (value); else if (name=="day") - mEnvironment.mWorld->setDay (value); + MWBase::Environment::get().getWorld()->setDay (value); else if (name=="month") - mEnvironment.mWorld->setMonth (value); + MWBase::Environment::get().getWorld()->setMonth (value); else - mEnvironment.mWorld->getGlobalVariable (name).mShort = value; + MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort = value; } void InterpreterContext::setGlobalLong (const std::string& name, int value) { if (name=="gamehour") - mEnvironment.mWorld->setHour (value); + MWBase::Environment::get().getWorld()->setHour (value); else if (name=="day") - mEnvironment.mWorld->setDay (value); + MWBase::Environment::get().getWorld()->setDay (value); else if (name=="month") - mEnvironment.mWorld->setMonth (value); + MWBase::Environment::get().getWorld()->setMonth (value); else - mEnvironment.mWorld->getGlobalVariable (name).mLong = value; + MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong = value; } void InterpreterContext::setGlobalFloat (const std::string& name, float value) { if (name=="gamehour") - mEnvironment.mWorld->setHour (value); + MWBase::Environment::get().getWorld()->setHour (value); else if (name=="day") - mEnvironment.mWorld->setDay (value); + MWBase::Environment::get().getWorld()->setDay (value); else if (name=="month") - mEnvironment.mWorld->setMonth (value); + MWBase::Environment::get().getWorld()->setMonth (value); else - mEnvironment.mWorld->getGlobalVariable (name).mFloat = value; + MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat = value; } bool InterpreterContext::isScriptRunning (const std::string& name) const { - return mEnvironment.mScriptManager->getGlobalScripts().isRunning (name); + return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name); } void InterpreterContext::startScript (const std::string& name) { - mEnvironment.mScriptManager->getGlobalScripts().addScript (name); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name); } void InterpreterContext::stopScript (const std::string& name) { - mEnvironment.mScriptManager->getGlobalScripts().removeScript (name); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript (name); } float InterpreterContext::getDistance (const std::string& name, const std::string& id) const @@ -193,7 +195,7 @@ namespace MWScript // TODO handle exterior cells (when ref and ref2 are located in different cells) const MWWorld::Ptr ref2 = getReference (id, false); - const MWWorld::Ptr ref = mEnvironment.mWorld->getPtr (name, true); + const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr (name, true); double diff[3]; @@ -234,7 +236,7 @@ namespace MWScript if (!mAction.get()) throw std::runtime_error ("activation failed, because no action to perform"); - mAction->execute (mEnvironment); + mAction->execute(); mActivationHandled = true; } @@ -247,7 +249,7 @@ namespace MWScript float InterpreterContext::getSecondsPassed() const { - return mEnvironment.mFrameDuration; + return MWBase::Environment::get().getFrameDuration(); } bool InterpreterContext::isDisabled (const std::string& id) const @@ -259,38 +261,13 @@ namespace MWScript void InterpreterContext::enable (const std::string& id) { MWWorld::Ptr ref = getReference (id, false); - mEnvironment.mWorld->enable (ref); + MWBase::Environment::get().getWorld()->enable (ref); } void InterpreterContext::disable (const std::string& id) { MWWorld::Ptr ref = getReference (id, false); - mEnvironment.mWorld->disable (ref); - } - - MWWorld::Environment& InterpreterContext::getEnvironment() - { - return mEnvironment; - } - - MWGui::WindowManager& InterpreterContext::getWindowManager() - { - return *mEnvironment.mWindowManager; - } - - MWInput::MWInputManager& InterpreterContext::getInputManager() - { - return *mEnvironment.mInputManager; - } - - MWWorld::World& InterpreterContext::getWorld() - { - return *mEnvironment.mWorld; - } - - MWSound::SoundManager& InterpreterContext::getSoundManager() - { - return *mEnvironment.mSoundManager; + MWBase::Environment::get().getWorld()->disable (ref); } MWWorld::Ptr InterpreterContext::getReference() diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 35b4a169d..40f53337d 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -6,7 +6,6 @@ #include #include "../mwworld/ptr.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/action.hpp" @@ -26,7 +25,6 @@ namespace MWScript class InterpreterContext : public Interpreter::Context { - MWWorld::Environment& mEnvironment; Locals *mLocals; MWWorld::Ptr mReference; @@ -40,8 +38,7 @@ namespace MWScript public: - InterpreterContext (MWWorld::Environment& environment, - MWScript::Locals *locals, MWWorld::Ptr reference); + InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference); ///< The ownership of \a locals is not transferred. 0-pointer allowed. virtual int getLocalShort (int index) const; @@ -110,18 +107,6 @@ namespace MWScript virtual void disable (const std::string& id = ""); - MWWorld::Environment& getEnvironment(); - - /// \todo remove the following functions (extentions should use getEnvironment instead) - - MWWorld::World& getWorld(); - - MWSound::SoundManager& getSoundManager(); - - MWGui::WindowManager& getWindowManager(); - - MWInput::MWInputManager& getInputManager(); - MWWorld::Ptr getReference(); ///< Reference, that the script is running from (can be empty) }; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a0770b9a8..4ba523937 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/class.hpp" #include "interpretercontext.hpp" @@ -100,7 +102,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - context.getWorld().toggleRenderMode (MWWorld::World::Render_CollisionDebug); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_CollisionDebug); context.report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); @@ -117,7 +119,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - context.getWorld().toggleRenderMode (MWWorld::World::Render_Wireframe); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_Wireframe); context.report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); @@ -133,7 +135,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - context.getWorld().toggleRenderMode (MWWorld::World::Render_Pathgrid); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_Pathgrid); context.report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); @@ -146,13 +148,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - context.getWorld().getFader()->fadeIn(time); + MWBase::Environment::get().getWorld()->getFader()->fadeIn(time); } }; @@ -162,13 +161,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - context.getWorld().getFader()->fadeOut(time); + MWBase::Environment::get().getWorld()->getFader()->fadeOut(time); } }; @@ -178,16 +174,13 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - Interpreter::Type_Float alpha = runtime[0].mFloat; runtime.pop(); Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - context.getWorld().getFader()->fadeTo(alpha, time); + MWBase::Environment::get().getWorld()->getFader()->fadeTo(alpha, time); } }; @@ -197,10 +190,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getWorld().toggleWater(); + MWBase::Environment::get().getWorld()->toggleWater(); } }; diff --git a/apps/openmw/mwscript/ref.hpp b/apps/openmw/mwscript/ref.hpp index 5ca1ea4d6..28093c4e5 100644 --- a/apps/openmw/mwscript/ref.hpp +++ b/apps/openmw/mwscript/ref.hpp @@ -5,6 +5,8 @@ #include +#include "../mwbase/environment.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/world.hpp" @@ -16,13 +18,10 @@ namespace MWScript { MWWorld::Ptr operator() (Interpreter::Runtime& runtime) const { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string id = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - return context.getWorld().getPtr (id, false); + return MWBase::Environment::get().getWorld()->getPtr (id, false); } }; diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index a5cc9e213..e16c2ec23 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "interpretercontext.hpp" namespace MWScript @@ -19,11 +21,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + bool enabled = MWBase::Environment::get().getWorld()->toggleSky(); + InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = context.getWorld().toggleSky(); - context.report (enabled ? "Sky -> On" : "Sky -> Off"); } }; @@ -34,10 +36,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getWorld().setMoonColour (false); + MWBase::Environment::get().getWorld()->setMoonColour (false); } }; @@ -47,10 +46,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.getWorld().setMoonColour (true); + MWBase::Environment::get().getWorld()->setMoonColour (true); } }; @@ -60,10 +56,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - runtime.push (context.getWorld().getMasserPhase()); + runtime.push (MWBase::Environment::get().getWorld()->getMasserPhase()); } }; @@ -73,42 +66,33 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - runtime.push (context.getWorld().getSecundaPhase()); + runtime.push (MWBase::Environment::get().getWorld()->getSecundaPhase()); } }; - + class OpGetCurrentWeather : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - - runtime.push (context.getWorld().getCurrentWeather()); + runtime.push (MWBase::Environment::get().getWorld()->getCurrentWeather()); } }; - + class OpChangeWeather : public Interpreter::Opcode0 { public: - + virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - std::string region = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - + Interpreter::Type_Integer id = runtime[0].mInteger; runtime.pop(); - - context.getWorld().changeWeather(region, id); + + MWBase::Environment::get().getWorld()->changeWeather(region, id); } }; diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index b4386a8a0..c2b45641a 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" #include "../mwsound/soundmanager.hpp" @@ -36,7 +38,7 @@ namespace MWScript std::string text = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getSoundManager().say (ptr, file); + MWBase::Environment::get().getSoundManager()->say (ptr, file); context.messageBox (text); } }; @@ -50,10 +52,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - - runtime.push (context.getSoundManager().sayDone (ptr)); + runtime.push (MWBase::Environment::get().getSoundManager()->sayDone (ptr)); } }; @@ -63,13 +62,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getSoundManager().streamMusic (sound); + MWBase::Environment::get().getSoundManager()->streamMusic (sound); } }; @@ -79,13 +75,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getSoundManager().playSound (sound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } }; @@ -95,9 +88,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -107,7 +97,7 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - context.getSoundManager().playSound (sound, volume, pitch); + MWBase::Environment::get().getSoundManager()->playSound (sound, volume, pitch); } }; @@ -124,13 +114,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getSoundManager().playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWSound::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWSound::Play_Loop : 0); } }; @@ -147,9 +134,6 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -159,7 +143,7 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - context.getSoundManager().playSound3D (ptr, sound, volume, pitch, mLoop ? MWSound::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWSound::Play_Loop : 0); } }; @@ -173,13 +157,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - context.getSoundManager().stopSound3D (ptr, sound); + MWBase::Environment::get().getSoundManager()->stopSound3D (ptr, sound); } }; @@ -192,13 +173,10 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - int index = runtime[0].mInteger; runtime.pop(); - runtime.push (context.getSoundManager().getSoundPlaying ( + runtime.push (MWBase::Environment::get().getSoundManager()->getSoundPlaying ( ptr, runtime.getStringLiteral (index))); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 239f8d768..cad52e593 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -7,8 +7,9 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwworld/class.hpp" -#include "../mwworld/environment.hpp" #include "../mwworld/player.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -351,11 +352,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { std::string factionID = ""; - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); + if(arg0==0) { - factionID = context.getEnvironment().mDialogueManager->getFaction(); + factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); } else { @@ -364,7 +364,7 @@ namespace MWScript } if(factionID != "") { - MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; @@ -380,11 +380,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { std::string factionID = ""; - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); + if(arg0==0) { - factionID = context.getEnvironment().mDialogueManager->getFaction(); + factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); } else { @@ -393,7 +392,7 @@ namespace MWScript } if(factionID != "") { - MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; @@ -413,11 +412,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { std::string factionID = ""; - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); + if(arg0==0) { - factionID = context.getEnvironment().mDialogueManager->getFaction(); + factionID = MWBase::Environment::get().getDialogueManager()->getFaction(); } else { @@ -426,7 +424,7 @@ namespace MWScript } if(factionID != "") { - MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) != MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) { MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] -1; @@ -461,9 +459,7 @@ namespace MWScript factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.begin()->first; } } - MWScript::InterpreterContext& context - = static_cast (runtime.getContext()); - MWWorld::Ptr player = context.getEnvironment().mWorld->getPlayer().getPlayer(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) != MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) @@ -481,7 +477,7 @@ namespace MWScript } } }; - + template class OpModDisposition : public Interpreter::Opcode0 { diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 730d9d9b2..4656efb6e 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -9,7 +9,8 @@ #include #include -#include "../mwworld/environment.hpp" +#include "../mwbase/environment.hpp" + #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -46,9 +47,8 @@ namespace MWSound { - SoundManager::SoundManager(bool useSound, MWWorld::Environment& environment) + SoundManager::SoundManager(bool useSound) : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) - , mEnvironment(environment) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -113,7 +113,7 @@ namespace MWSound std::string SoundManager::lookup(const std::string &soundId, float &volume, float &min, float &max) { - const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId); + const ESM::Sound *snd = MWBase::Environment::get().getWorld()->getStore().sounds.search(soundId); if(snd == NULL) throw std::runtime_error(std::string("Failed to lookup sound ")+soundId); @@ -380,7 +380,7 @@ namespace MWSound void SoundManager::updateRegionSound(float duration) { - MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); + MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); static int total = 0; static std::string regionName = ""; static float timePassed = 0.0; @@ -397,7 +397,7 @@ namespace MWSound total = 0; } - const ESM::Region *regn = mEnvironment.mWorld->getStore().regions.find(regionName); + const ESM::Region *regn = MWBase::Environment::get().getWorld()->getStore().regions.find(regionName); std::vector::const_iterator soundIter; if(total == 0) { @@ -445,8 +445,8 @@ namespace MWSound if(!isMusicPlaying()) startRandomTitle(); - const ESM::Cell *cell = mEnvironment.mWorld->getPlayer().getPlayer().getCell()->cell; - Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera(); + const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell; + Ogre::Camera *cam = MWBase::Environment::get().getWorld()->getPlayer().getRenderer()->getCamera(); Ogre::Vector3 nPos, nDir, nUp; nPos = cam->getRealPosition(); nDir = cam->getRealDirection(); diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index d64db299b..8afd488e1 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -16,11 +16,6 @@ namespace Ogre class Camera; } -namespace MWWorld -{ - struct Environment; -} - namespace MWSound { class Sound_Output; @@ -52,8 +47,6 @@ namespace MWSound { Ogre::ResourceGroupManager& mResourceMgr; - MWWorld::Environment& mEnvironment; - std::auto_ptr mOutput; float mMasterVolume; @@ -82,7 +75,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(bool useSound, MWWorld::Environment& environment); + SoundManager(bool useSound); ~SoundManager(); void stopMusic(); diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 155819335..d5cf12779 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -3,8 +3,6 @@ namespace MWWorld { - class Environment; - /// \brief Abstract base for actions class Action { @@ -18,7 +16,7 @@ namespace MWWorld virtual ~Action() {} - virtual void execute (Environment& environment) = 0; + virtual void execute() = 0; }; } diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index bbe954049..b1e2e1fc3 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -1,8 +1,9 @@ #include "actiontake.hpp" +#include "../mwbase/environment.hpp" + #include "class.hpp" -#include "environment.hpp" #include "world.hpp" #include "containerstore.hpp" @@ -10,14 +11,14 @@ namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : mObject (object) {} - void ActionTake::execute (Environment& environment) + void ActionTake::execute() { // insert into player's inventory - MWWorld::Ptr player = environment.mWorld->getPtr ("player", true); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); MWWorld::Class::get (player).getContainerStore (player).add (mObject); // remove from world - environment.mWorld->deleteObject (mObject); + MWBase::Environment::get().getWorld()->deleteObject (mObject); } } diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index 509ebc6bb..f495fc3c4 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -14,7 +14,7 @@ namespace MWWorld ActionTake (const MWWorld::Ptr& object); - virtual void execute (Environment& environment); + virtual void execute(); }; } diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 7d38c22fd..b33b78832 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -1,7 +1,7 @@ #include "actiontalk.hpp" -#include "environment.hpp" +#include "../mwbase/environment.hpp" #include "../mwdialogue/dialoguemanager.hpp" @@ -9,8 +9,8 @@ namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : mActor (actor) {} - void ActionTalk::execute (Environment& environment) + void ActionTalk::execute() { - environment.mDialogueManager->startDialogue (mActor); + MWBase::Environment::get().getDialogueManager()->startDialogue (mActor); } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index a60a61660..1b7b9b6d6 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -15,7 +15,7 @@ namespace MWWorld ActionTalk (const Ptr& actor); ///< \param actor The actor the player is talking to - virtual void execute (Environment& environment); + virtual void execute(); }; } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 207e2c50e..6ebbd7b7f 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -1,7 +1,8 @@ #include "actionteleport.hpp" -#include "environment.hpp" +#include "../mwbase/environment.hpp" + #include "world.hpp" namespace MWWorld @@ -11,11 +12,11 @@ namespace MWWorld : mCellName (cellName), mPosition (position) {} - void ActionTeleportPlayer::execute (Environment& environment) + void ActionTeleportPlayer::execute() { if (mCellName.empty()) - environment.mWorld->changeToExteriorCell (mPosition); + MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); else - environment.mWorld->changeToInteriorCell (mCellName, mPosition); + MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); } } diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index e4c972a9e..00efdc876 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -19,7 +19,7 @@ namespace MWWorld ActionTeleportPlayer (const std::string& cellName, const ESM::Position& position); ///< If cellName is empty, an exterior cell is asumed. - virtual void execute (Environment& environment); + virtual void execute(); }; } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index d49b98d0f..c53ebcfd0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -27,17 +27,17 @@ namespace MWWorld } - void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const + void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const { } - void Class::enable (const Ptr& ptr, MWWorld::Environment& environment) const + void Class::enable (const Ptr& ptr) const { } - void Class::disable (const Ptr& ptr, MWWorld::Environment& environment) const + void Class::disable (const Ptr& ptr) const { } @@ -62,14 +62,12 @@ namespace MWWorld throw std::runtime_error ("class does not have item health"); } - boost::shared_ptr Class::activate (const Ptr& ptr, const Ptr& actor, - const Environment& environment) const + boost::shared_ptr Class::activate (const Ptr& ptr, const Ptr& actor) const { return boost::shared_ptr (new NullAction); } - boost::shared_ptr Class::use (const Ptr& ptr, - const Environment& environment) const + boost::shared_ptr Class::use (const Ptr& ptr) const { return boost::shared_ptr (new NullAction); } @@ -134,7 +132,7 @@ namespace MWWorld return std::make_pair (std::vector(), false); } - int Class::getEquipmentSkill (const Ptr& ptr, const Environment& environment) const + int Class::getEquipmentSkill (const Ptr& ptr) const { return -1; } @@ -164,12 +162,12 @@ namespace MWWorld sClasses.insert (std::make_pair (key, instance)); } - std::string Class::getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const + std::string Class::getUpSoundId (const Ptr& ptr) const { throw std::runtime_error ("class does not have an up sound"); } - std::string Class::getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const + std::string Class::getDownSoundId (const Ptr& ptr) const { throw std::runtime_error ("class does not have an down sound"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e474e9b92..622d9eeae 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -33,7 +33,6 @@ namespace MWMechanics namespace MWWorld { class Ptr; - class Environment; class ContainerStore; class InventoryStore; @@ -65,15 +64,15 @@ namespace MWWorld /// (default implementation: throw an exception) virtual void insertObjectRendering (const Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; - virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const; + virtual void insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics) const; ///< Add reference into a cell for rendering (default implementation: don't render anything). - virtual void enable (const Ptr& ptr, MWWorld::Environment& environment) const; + virtual void enable (const Ptr& ptr) const; ///< Enable reference; only does the non-rendering part (default implementation: ignore) /// \attention This is not the same as the script instruction with the same name. References /// should only be enabled while in an active cell. - virtual void disable (const Ptr& ptr, MWWorld::Environment& environment) const; + virtual void disable (const Ptr& ptr) const; ///< Enable reference; only does the non-rendering part (default implementation: ignore) /// \attention This is not the same as the script instruction with the same name. References /// should only be enabled while in an active cell. @@ -97,11 +96,10 @@ namespace MWWorld ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exceoption) - virtual boost::shared_ptr activate (const Ptr& ptr, const Ptr& actor, - const Environment& environment) const; + virtual boost::shared_ptr activate (const Ptr& ptr, const Ptr& actor) const; ///< Generate action for activation (default implementation: return a null action). - virtual boost::shared_ptr use (const Ptr& ptr, const Environment& environment) + virtual boost::shared_ptr use (const Ptr& ptr) const; ///< Generate action for using via inventory menu (default implementation: return a /// null action). @@ -149,7 +147,7 @@ namespace MWWorld /// /// Default implementation: return (empty vector, false). - virtual int getEquipmentSkill (const Ptr& ptr, const Environment& environment) + virtual int getEquipmentSkill (const Ptr& ptr) const; /// Return the index of the skill this item corresponds to when equiopped or -1, if there is /// no such skill. @@ -167,11 +165,11 @@ namespace MWWorld static void registerClass (const std::string& key, boost::shared_ptr instance); - virtual std::string getUpSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getUpSoundId (const Ptr& ptr) const; ///< Return the up sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) - virtual std::string getDownSoundId (const Ptr& ptr, const MWWorld::Environment& environment) const; + virtual std::string getDownSoundId (const Ptr& ptr) const; ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) }; diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp deleted file mode 100644 index 8c4a001e0..000000000 --- a/apps/openmw/mwworld/environment.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef GAME_WORLD_INVIRONMENT_H -#define GAME_WORLD_INVIRONMENT_H - -namespace MWSound -{ - class SoundManager; -} - -namespace MWScript -{ - class ScriptManager; -} - -namespace MWGui -{ - class WindowManager; -} - -namespace MWMechanics -{ - class MechanicsManager; -} - -namespace MWDialogue -{ - class DialogueManager; - class Journal; -} - -namespace MWInput -{ - struct MWInputManager; -} - -namespace MWWorld -{ - class World; - - ///< Collection of script-accessable sub-systems - class Environment - { - public: - Environment() - : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), - mMechanicsManager (0), mDialogueManager (0), mJournal (0), mFrameDuration (0), - mInputManager (0) - {} - - World *mWorld; - MWSound::SoundManager *mSoundManager; - MWScript::ScriptManager *mScriptManager; - MWGui::WindowManager *mWindowManager; - MWMechanics::MechanicsManager *mMechanicsManager; - MWDialogue::DialogueManager *mDialogueManager; - MWDialogue::Journal *mJournal; - float mFrameDuration; - - // For setting GUI mode - MWInput::MWInputManager *mInputManager; - }; -} - -#endif diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 230f7d69a..b93a62e4e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -72,7 +72,7 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite /// \todo restack item previously in this slot (if required) /// \todo unstack item pointed to by iterator if required) - + mSlots[slot] = iterator; flagAsModified(); @@ -96,8 +96,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } -void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats, - const Environment& environment) +void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) { TSlots slots; initSlots (slots); @@ -105,7 +104,7 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats, for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; - int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test, environment); + int testSkill = MWWorld::Class::get (test).getEquipmentSkill (test); std::pair, bool> itemsSlots = MWWorld::Class::get (*iter).getEquipmentSlots (*iter); @@ -125,7 +124,7 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats, { // check skill int oldSkill = - MWWorld::Class::get (old).getEquipmentSkill (old, environment); + MWWorld::Class::get (old).getEquipmentSkill (old); if (testSkill!=-1 || oldSkill!=-1 || testSkill!=oldSkill) { diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 60b89b0b4..5eeaf570d 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -10,8 +10,6 @@ namespace MWMechanics namespace MWWorld { - class Environment; - ///< \brief Variant of the ContainerStore for NPCs class InventoryStore : public ContainerStore { @@ -64,7 +62,7 @@ namespace MWWorld ContainerStoreIterator getSlot (int slot); - void autoEquip (const MWMechanics::NpcStats& stats, const Environment& environment); + void autoEquip (const MWMechanics::NpcStats& stats); ///< Auto equip items according to stats and item value. }; } diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index 820fc4538..c8e3368e4 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -10,7 +10,7 @@ namespace MWWorld { public: - virtual void execute (Environment& environment) {} + virtual void execute() {} }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2123b4799..abb988c83 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,7 @@ #include "scene.hpp" #include "world.hpp" +#include "../mwbase/environment.hpp" #include "../mwmechanics/mechanicsmanager.hpp" @@ -9,7 +10,6 @@ #include "../mwgui/window_manager.hpp" #include "ptr.hpp" -#include "environment.hpp" #include "player.hpp" #include "class.hpp" @@ -18,7 +18,7 @@ namespace { template -void insertCellRefList(MWRender::RenderingManager& rendering, MWWorld::Environment& environment, +void insertCellRefList(MWRender::RenderingManager& rendering, T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) { if (!cellRefList.list.empty()) @@ -36,8 +36,8 @@ void insertCellRefList(MWRender::RenderingManager& rendering, MWWorld::Environme try { rendering.addObject(ptr); - class_.insertObject(ptr, physics, environment); - class_.enable (ptr, environment); + class_.insertObject(ptr, physics); + class_.enable (ptr); } catch (const std::exception& e) { @@ -86,12 +86,12 @@ namespace MWWorld //mPhysics->removeObject("Unnamed_43"); mWorld->getLocalScripts().clearCell (*iter); - mEnvironment.mMechanicsManager->dropActors (*iter); - mEnvironment.mSoundManager->stopSound (*iter); + MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); + MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); - - + + } void Scene::loadCell (Ptr::CellStore *cell) @@ -104,7 +104,7 @@ namespace MWWorld std::pair result = mActiveCells.insert(cell); if(result.second){ - insertCell(*cell, mEnvironment); + insertCell(*cell); mRendering.cellAdded(cell); mRendering.configureAmbient(*cell); mRendering.requestMap(cell); @@ -122,10 +122,10 @@ namespace MWWorld mWorld->getPlayer().setCell (cell); // TODO orientation - mEnvironment.mMechanicsManager->addActor (mWorld->getPlayer().getPlayer()); - mEnvironment.mMechanicsManager->watchActor (mWorld->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->addActor (mWorld->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->watchActor (mWorld->getPlayer().getPlayer()); - mEnvironment.mWindowManager->changeCell( mCurrentCell ); + MWBase::Environment::get().getWindowManager()->changeCell( mCurrentCell ); } void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) @@ -133,7 +133,7 @@ namespace MWWorld mRendering.preCellChange(mCurrentCell); // remove active - mEnvironment.mMechanicsManager->removeActor (mWorld->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->removeActor (mWorld->getPlayer().getPlayer()); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -207,8 +207,8 @@ namespace MWWorld } //We need the ogre renderer and a scene node. - Scene::Scene (Environment& environment, World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), mEnvironment (environment), mWorld(world), + Scene::Scene (World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics) + : mCurrentCell (0), mCellChanged (false), mWorld(world), mPhysics(physics), mRendering(rendering) { } @@ -243,12 +243,12 @@ namespace MWWorld Ptr::CellStore *cell = mWorld->getInterior(cellName); loadCell (cell); - + // adjust player mCurrentCell = cell; playerCellChange (cell, position); - + // adjust fog mRendering.configureFog(*cell); @@ -278,30 +278,29 @@ namespace MWWorld mCellChanged = false; } -void Scene::insertCell(ESMS::CellStore &cell, - MWWorld::Environment& environment) +void Scene::insertCell(ESMS::CellStore &cell) { // Loop through all references in the cell - insertCellRefList(mRendering, environment, cell.activators, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.potions, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.appas, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.armors, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.books, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.clothes, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.containers, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.creatures, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.doors, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.ingreds, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.creatureLists, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.itemLists, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.lights, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.lockpicks, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.miscItems, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.npcs, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.probes, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.repairs, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.statics, cell, *mPhysics); - insertCellRefList(mRendering, environment, cell.weapons, cell, *mPhysics); + insertCellRefList(mRendering, cell.activators, cell, *mPhysics); + insertCellRefList(mRendering, cell.potions, cell, *mPhysics); + insertCellRefList(mRendering, cell.appas, cell, *mPhysics); + insertCellRefList(mRendering, cell.armors, cell, *mPhysics); + insertCellRefList(mRendering, cell.books, cell, *mPhysics); + insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); + insertCellRefList(mRendering, cell.containers, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); + insertCellRefList(mRendering, cell.doors, cell, *mPhysics); + insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.lights, cell, *mPhysics); + insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); + insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); + insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); + insertCellRefList(mRendering, cell.probes, cell, *mPhysics); + insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); + insertCellRefList(mRendering, cell.statics, cell, *mPhysics); + insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 4d1bd6fb5..1a9f2f271 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -46,7 +46,6 @@ namespace MWRender namespace MWWorld { - class Environment; class Player; class Scene @@ -62,7 +61,6 @@ namespace MWWorld Ptr::CellStore* mCurrentCell; // the cell, the player is in CellStoreCollection mActiveCells; bool mCellChanged; - Environment& mEnvironment; World *mWorld; PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; @@ -73,7 +71,7 @@ namespace MWWorld public: - Scene (Environment& environment, World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics); + Scene (World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics); ~Scene(); @@ -100,7 +98,7 @@ namespace MWWorld void markCellAsUnchanged(); - void insertCell(ESMS::CellStore &cell, MWWorld::Environment& environment); + void insertCell(ESMS::CellStore &cell); void update (float duration); }; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index fb0480171..803fce1e1 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -9,7 +9,9 @@ #include #include -#include +#include + +#include "../mwbase/environment.hpp" using namespace Ogre; using namespace MWWorld; @@ -34,15 +36,14 @@ const float WeatherGlobals::mThunderFrequency = .4; const float WeatherGlobals::mThunderThreshold = 0.6; const float WeatherGlobals::mThunderSoundDelay = 0.25; -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::Environment* env) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0) { mRendering = rendering; - mEnvironment = env; - + #define clr(r,g,b) ColourValue(r/255.f, g/255.f, b/255.f) - + /// \todo read these from Morrowind.ini Weather clear; clear.mCloudTexture = "tx_sky_clear.dds"; @@ -71,7 +72,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E clear.mCloudSpeed = 1.25; clear.mGlareView = 1.0; mWeatherSettings["clear"] = clear; - + Weather cloudy; cloudy.mCloudTexture = "tx_sky_cloudy.dds"; cloudy.mCloudsMaximumPercent = 1.0; @@ -99,7 +100,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E cloudy.mCloudSpeed = 2; cloudy.mGlareView = 1.0; mWeatherSettings["cloudy"] = cloudy; - + Weather foggy; foggy.mCloudTexture = "tx_sky_foggy.dds"; foggy.mCloudsMaximumPercent = 1.0; @@ -127,7 +128,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E foggy.mCloudSpeed = 1.25; foggy.mGlareView = 0.25; mWeatherSettings["foggy"] = foggy; - + Weather thunderstorm; thunderstorm.mCloudTexture = "tx_sky_thunder.dds"; thunderstorm.mCloudsMaximumPercent = 0.66; @@ -156,7 +157,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E thunderstorm.mGlareView = 0; thunderstorm.mRainLoopSoundID = "rain heavy"; mWeatherSettings["thunderstorm"] = thunderstorm; - + Weather rain; rain.mCloudTexture = "tx_sky_rainy.dds"; rain.mCloudsMaximumPercent = 0.66; @@ -185,7 +186,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E rain.mGlareView = 0; rain.mRainLoopSoundID = "rain"; mWeatherSettings["rain"] = rain; - + Weather overcast; overcast.mCloudTexture = "tx_sky_overcast.dds"; overcast.mCloudsMaximumPercent = 1.0; @@ -213,7 +214,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E overcast.mCloudSpeed = 1.5; overcast.mGlareView = 0; mWeatherSettings["overcast"] = overcast; - + Weather ashstorm; ashstorm.mCloudTexture = "tx_sky_ashstorm.dds"; ashstorm.mCloudsMaximumPercent = 1.0; @@ -242,7 +243,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E ashstorm.mGlareView = 0; ashstorm.mAmbientLoopSoundID = "ashstorm"; mWeatherSettings["ashstorm"] = ashstorm; - + Weather blight; blight.mCloudTexture = "tx_sky_blight.dds"; blight.mCloudsMaximumPercent = 1.0; @@ -300,7 +301,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E snow.mCloudSpeed = 1.5; snow.mGlareView = 0; mWeatherSettings["snow"] = snow; - + Weather blizzard; blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; blizzard.mCloudsMaximumPercent = 1.0; @@ -484,15 +485,15 @@ WeatherResult WeatherManager::transition(float factor) void WeatherManager::update(float duration) { - mWeatherUpdateTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); + mWeatherUpdateTime -= duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - bool exterior = (mEnvironment->mWorld->isCellExterior() || mEnvironment->mWorld->isCellQuasiExterior()); + bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); if (exterior) { - std::string regionstr = mEnvironment->mWorld->getPlayer().getPlayer().getCell()->cell->region; + std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->region; boost::algorithm::to_lower(regionstr); - + if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { mCurrentRegion = regionstr; @@ -505,7 +506,7 @@ void WeatherManager::update(float duration) else { // get weather probabilities for the current region - const ESM::Region *region = mEnvironment->mWorld->getStore().regions.find (regionstr); + const ESM::Region *region = MWBase::Environment::get().getWorld()->getStore().regions.find (regionstr); float clear = region->data.clear/255.f; float cloudy = region->data.cloudy/255.f; @@ -553,7 +554,7 @@ void WeatherManager::update(float duration) if (mNextWeather != "") { - mRemainingTransitionTime -= duration * mEnvironment->mWorld->getTimeScaleFactor(); + mRemainingTransitionTime -= duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor(); if (mRemainingTransitionTime < 0) { mCurrentWeather = mNextWeather; @@ -588,8 +589,8 @@ void WeatherManager::update(float duration) int facing = (mHour > 13.f) ? 1 : -1; Vector3 final( - -(1-height)*facing, - -(1-height)*facing, + -(1-height)*facing, + -(1-height)*facing, height); mRendering->setSunDirection(final); @@ -609,13 +610,13 @@ void WeatherManager::update(float duration) float moonHeight = 1-std::abs((night-0.5)*2); int facing = (mHour > 0.f && mHour<12.f) ? 1 : -1; Vector3 masser( - (1-moonHeight)*facing, - (1-moonHeight)*facing, + (1-moonHeight)*facing, + (1-moonHeight)*facing, moonHeight); Vector3 secunda( - (1-moonHeight)*facing*0.8, - (1-moonHeight)*facing*1.25, + (1-moonHeight)*facing*0.8, + (1-moonHeight)*facing*1.25, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); @@ -676,7 +677,7 @@ void WeatherManager::update(float duration) else if (sound == 1) soundname = WeatherGlobals::mThunderSoundID1; else if (sound == 2) soundname = WeatherGlobals::mThunderSoundID2; else if (sound == 3) soundname = WeatherGlobals::mThunderSoundID3; - mEnvironment->mSoundManager->playSound(soundname, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound(soundname, 1.0, 1.0); mThunderSoundDelay = 1000; } @@ -729,7 +730,7 @@ void WeatherManager::update(float duration) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(ambientSnd); - mEnvironment->mSoundManager->playSound(ambientSnd, 1.0, 1.0, true); + MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, true); } } @@ -740,7 +741,7 @@ void WeatherManager::update(float duration) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(rainSnd); - mEnvironment->mSoundManager->playSound(rainSnd, 1.0, 1.0, true); + MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, true); } } @@ -750,7 +751,7 @@ void WeatherManager::update(float duration) { if ( *it != ambientSnd && *it != rainSnd) { - mEnvironment->mSoundManager->stopSound(*it); + MWBase::Environment::get().getSoundManager()->stopSound(*it); it = mSoundsPlaying.erase(it); } else @@ -772,7 +773,7 @@ void WeatherManager::setDate(const int day, const int month) unsigned int WeatherManager::getWeatherID() const { // Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather - + if (mCurrentWeather == "clear") return 0; else if (mCurrentWeather == "cloudy") @@ -793,7 +794,7 @@ unsigned int WeatherManager::getWeatherID() const return 8; else if (mCurrentWeather == "blizzard") return 9; - + else return 0; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index b9b40e6fa..5e0388751 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -11,8 +11,6 @@ namespace MWRender namespace MWWorld { - class Environment; - /// Global weather manager properties (according to INI) struct WeatherGlobals { @@ -67,8 +65,8 @@ namespace MWWorld Snow Gravity Scale=0.1 Snow High Kill=700 Snow Low Kill=150 - - + + [Moons] Masser Size=94 Masser Fade In Start=14 @@ -94,14 +92,14 @@ namespace MWWorld Secunda Moon Shadow Early Fade Angle=0.5 Script Color=255,20,20 */ - + static const float mSunriseTime; static const float mSunsetTime; static const float mSunriseDuration; static const float mSunsetDuration; - + static const float mWeatherUpdateTime; - + // morrowind sets these per-weather, but since they are only used by 'thunderstorm' // weather setting anyway, we can just as well set them globally static const float mThunderFrequency; @@ -119,154 +117,153 @@ namespace MWWorld Ogre::String mCloudTexture; Ogre::String mNextCloudTexture; float mCloudBlendFactor; - + Ogre::ColourValue mFogColor; - + Ogre::ColourValue mAmbientColor; - + Ogre::ColourValue mSkyColor; - + Ogre::ColourValue mSunColor; - + Ogre::ColourValue mSunDiscColor; - + float mFogDepth; - + float mWindSpeed; - + float mCloudSpeed; - + float mCloudOpacity; - + float mGlareView; - + bool mNight; // use night skybox float mNightFade; // fading factor for night skybox - + Ogre::String mAmbientLoopSoundID; }; - - + + /// Defines a single weather setting (according to INI) struct Weather { Ogre::String mCloudTexture; - - // Sky (atmosphere) colors + + // Sky (atmosphere) colors Ogre::ColourValue mSkySunriseColor, mSkyDayColor, mSkySunsetColor, mSkyNightColor; - + // Fog colors Ogre::ColourValue mFogSunriseColor, mFogDayColor, mFogSunsetColor, mFogNightColor; - + // Ambient lighting colors Ogre::ColourValue mAmbientSunriseColor, mAmbientDayColor, mAmbientSunsetColor, mAmbientNightColor; - + // Sun (directional) lighting colors Ogre::ColourValue mSunSunriseColor, mSunDayColor, mSunSunsetColor, mSunNightColor; - + // Fog depth/density float mLandFogDayDepth, mLandFogNightDepth; - + // Color modulation for the sun itself during sunset (not completely sure) Ogre::ColourValue mSunDiscSunsetColor; - + // Duration of weather transition (in days) float mTransitionDelta; - + // No idea what this one is used for? float mWindSpeed; - + // Cloud animation speed multiplier float mCloudSpeed; - + // Multiplier for clouds transparency float mCloudsMaximumPercent; - + // Value between 0 and 1, defines the strength of the sun glare effect float mGlareView; - + // Sound effect // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) Ogre::String mAmbientLoopSoundID; - + // Rain sound effect Ogre::String mRainLoopSoundID; - + /// \todo disease chance }; - + /// /// Interface for weather settings /// class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*, MWWorld::Environment*); - + WeatherManager(MWRender::RenderingManager*); + /** * Change the weather in the specified region * @param region that should be changed * @param ID of the weather setting to shift to */ void changeWeather(const std::string& region, const unsigned int id); - + /** * Per-frame update * @param duration */ void update(float duration); - + void setHour(const float hour); - + void setDate(const int day, const int month); - + unsigned int getWeatherID() const; - + private: float mHour; int mDay, mMonth; - + MWRender::RenderingManager* mRendering; - MWWorld::Environment* mEnvironment; - + std::map mWeatherSettings; std::map mRegionOverrides; std::vector mSoundsPlaying; - + Ogre::String mCurrentWeather; Ogre::String mNextWeather; - + std::string mCurrentRegion; - + bool mFirstUpdate; - + float mWeatherUpdateTime; - + float mRemainingTransitionTime; - + float mThunderFlash; float mThunderChance; float mThunderChanceNeeded; float mThunderSoundDelay; - + WeatherResult transition(const float factor); WeatherResult getResult(const Ogre::String& weather); - + void setWeather(const Ogre::String& weather, bool instant=false); }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 1c64039d4..66eedcb84 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -6,6 +6,8 @@ #include #include +#include "../mwbase/environment.hpp" + #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -15,7 +17,6 @@ #include "ptr.hpp" -#include "environment.hpp" #include "class.hpp" #include "player.hpp" #include "weather.hpp" @@ -174,18 +175,18 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, - bool newGame, Environment& environment, const std::string& encoding, std::map fallbackMap) + const std::string& master, const boost::filesystem::path& resDir, bool newGame, + const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), - mSky (true), mEnvironment (environment), mNextDynamicRecord (0), mCells (mStore, mEsm, *this), + mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm, *this), mNumFacing(0) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); - mRendering = new MWRender::RenderingManager(renderer, resDir, mPhysEngine, environment); + mRendering = new MWRender::RenderingManager(renderer, resDir, mPhysEngine); - mWeatherManager = new MWWorld::WeatherManager(mRendering, &environment); + mWeatherManager = new MWWorld::WeatherManager(mRendering); boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); @@ -209,7 +210,7 @@ namespace MWWorld mGlobalVariables->setInt ("chargenstate", 1); } - mWorldScene = new Scene(environment, this, *mRendering, mPhysics); + mWorldScene = new Scene(this, *mRendering, mPhysics); setFallbackValues(fallbackMap); @@ -357,7 +358,7 @@ namespace MWWorld //render->enable (reference.getRefData().getHandle()); if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end()) - Class::get (reference).enable (reference, mEnvironment); + Class::get (reference).enable (reference); } @@ -372,8 +373,8 @@ namespace MWWorld //render->disable (reference.getRefData().getHandle()); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end()){ - Class::get (reference).disable (reference, mEnvironment); - mEnvironment.mSoundManager->stopSound3D (reference); + Class::get (reference).disable (reference); + MWBase::Environment::get().getSoundManager()->stopSound3D (reference); } @@ -547,7 +548,7 @@ namespace MWWorld if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end()){ // Class::get (ptr).disable (ptr, mEnvironment); /// \todo this line needs to be removed - mEnvironment.mSoundManager->stopSound3D (ptr); + MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->removeObject (ptr.getRefData().getHandle()); mRendering->removeObject(ptr); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 8dd370ad7..77e5bcef6 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -51,7 +51,6 @@ namespace MWRender namespace MWWorld { class WeatherManager; - class Environment; class Player; /// \brief The game world and its visual representation @@ -81,7 +80,6 @@ namespace MWWorld MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; - Environment& mEnvironment; int mNextDynamicRecord; Cells mCells; @@ -111,7 +109,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, - Environment& environment, const std::string& encoding, std::map fallbackMap); + const std::string& encoding, std::map fallbackMap); ~World(); From 9f1199ee7e2e5e92c22a416ad5a707d9241b50d9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Apr 2012 15:29:15 +0200 Subject: [PATCH 181/185] removing a using directive from a header file --- apps/openmw/mwgui/dialogue.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5b8439758..61e8c124c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -18,8 +18,6 @@ namespace MWGui { class DialogueHistory; - using namespace MyGUI; - class DialogueWindow: public WindowBase { public: @@ -28,7 +26,7 @@ namespace MWGui void open(); // Events - typedef delegates::CMultiDelegate0 EventHandle_Void; + typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; /** Event : Dialog finished, OK button clicked.\n signature : void method()\n From f4428097f951d0c021bb46753e78cf8700c5aa27 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Apr 2012 15:37:38 +0200 Subject: [PATCH 182/185] removing more cout spam --- apps/openmw/mwclass/npc.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c053ad130..afb904f51 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -105,10 +105,10 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - - + + renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); - + } void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const @@ -296,7 +296,6 @@ namespace MWClass void Npc::registerSelf() { boost::shared_ptr instance (new Npc); - std::cout << "class npc:" << typeid (ESM::NPC).name(); registerClass (typeid (ESM::NPC).name(), instance); } } From d5e52e46ea58fb10bbe1cc9171f9aef428947b3f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Apr 2012 09:19:41 +0200 Subject: [PATCH 183/185] removing even more cout spam (thanks to scrawl for finding this one) --- apps/openmw/mwworld/player.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d24780ec1..5ed9aeaff 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -24,8 +24,6 @@ namespace MWWorld float* playerPos = mPlayer.mData.getPosition().pos; playerPos[0] = playerPos[1] = playerPos[2] = 0; - std::cout << renderer->getHandle(); - mPlayer.mData.setBaseNode(renderer->getNode()); /// \todo Do not make a copy of classes defined in esm/p records. mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); From 4ce83badc9860cc965cbdf79c7d859517d16cc96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Apr 2012 20:42:53 +0200 Subject: [PATCH 184/185] flickering lights --- apps/openmw/mwrender/objects.cpp | 117 +++++++++++++++++----- apps/openmw/mwrender/objects.hpp | 33 ++++-- apps/openmw/mwrender/renderingmanager.cpp | 2 - apps/openmw/mwworld/weather.cpp | 1 - components/esm/loadligh.hpp | 2 +- 5 files changed, 120 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index a79d72989..86a845a27 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -192,19 +192,43 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f Ogre::Light *light = mRenderer.getScene()->createLight(); light->setDiffuseColour (r, g, b); + ESMS::LiveCellRef *ref = + ptr.get(); + LightInfo info; info.name = light->getName(); info.radius = radius; info.colour = Ogre::ColourValue(r, g, b); - mLights.push_back(info); + if (ref->base->data.flags & ESM::Light::Negative) + info.colour *= -1; + info.interior = (ptr.getCell()->cell->data.flags & ESM::Cell::Interior); + + if (ref->base->data.flags & ESM::Light::Flicker) + info.type = LT_Flicker; + else if (ref->base->data.flags & ESM::Light::FlickerSlow) + info.type = LT_FlickerSlow; + else if (ref->base->data.flags & ESM::Light::Pulse) + info.type = LT_Pulse; + else if (ref->base->data.flags & ESM::Light::PulseSlow) + info.type = LT_PulseSlow; + else + info.type = LT_Normal; + + // random starting phase for the animation + info.time = Ogre::Math::RangeRandom(0, 2 * M_PI); + + // adjust the lights depending if we're in an interior or exterior cell + // quadratic means the light intensity falls off quite fast, resulting in a + // dark, atmospheric environment (perfect for exteriors) + // for interiors, we want more "warm" lights, so use linear attenuation. bool quadratic = false; if (!lightOutQuadInLin) quadratic = lightQuadratic; else { - quadratic = !mInterior; + quadratic = !info.interior; } if (!quadratic) @@ -221,6 +245,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f } insert->attachObject(light); + mLights.push_back(info); } bool Objects::deleteObject (const MWWorld::Ptr& ptr) @@ -329,17 +354,8 @@ void Objects::disableLights() } } -void Objects::setInterior(const bool interior) -{ - mInterior = interior; -} - void Objects::update(const float dt) { - // adjust the lights depending if we're in an interior or exterior cell - // quadratic means the light intensity falls off quite fast, resulting in a - // dark, atmospheric environment (perfect for exteriors) - // for interiors, we want more "warm" lights, so use linear attenuation. std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { @@ -347,26 +363,77 @@ void Objects::update(const float dt) { Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); - bool quadratic = false; - if (!lightOutQuadInLin) - quadratic = lightQuadratic; - else + // Light animation (pulse & flicker) + it->time += dt; + const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20; + float pulseConstant; + + // These formulas are just guesswork, but they work pretty well + if (it->type == LT_Normal) { - quadratic = !mInterior; + // Less than 1/255 light modifier for a constant light: + pulseConstant = (const float)(1.0 + sin(phase) / 255.0 ); } - - if (!quadratic) + else if (it->type == LT_Flicker) { - float radius = it->radius * lightLinearRadiusMult; - float attenuation = lightLinearValue / it->radius; - light->setAttenuation(radius*10, 0, attenuation, 0); + // Let's do a 50% -> 100% sine wave pulse over 1 second: + // This is 75% +/- 25% + pulseConstant = (const float)(0.75 + sin(phase) * 0.25); + + // Then add a 25% flicker variation: + it->resetTime -= dt; + if (it->resetTime < 0) + { + it->flickerVariation = (rand() % 1000) / 1000 * 0.25; + it->resetTime = 0.5; + } + if (it->resetTime > 0.25) + { + pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f; + } + else + { + pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f); + } } - else + else if (it->type == LT_FlickerSlow) + { + // Let's do a 50% -> 100% sine wave pulse over 1 second: + // This is 75% +/- 25% + pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25); + + // Then add a 25% flicker variation: + it->resetTime -= dt; + if (it->resetTime < 0) + { + it->flickerVariation = (rand() % 1000) / 1000 * 0.25; + it->resetTime = 0.5; + } + if (it->resetTime > 0.5) + { + pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime; + } + else + { + pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime); + } + } + else if (it->type == LT_Pulse) { - float radius = it->radius * lightQuadraticRadiusMult; - float attenuation = lightQuadraticValue / pow(it->radius, 2); - light->setAttenuation(radius*10, 0, 0, attenuation); + // Let's do a 75% -> 125% sine wave pulse over 1 second: + // This is 100% +/- 25% + pulseConstant = (const float)(1.0 + sin(phase) * 0.25); } + else if (it->type == LT_PulseSlow) + { + // Let's do a 75% -> 125% sine wave pulse over 1 second: + // This is 100% +/- 25% + pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25); + } + else + assert(0 && "Invalid light type"); + + light->setDiffuseColour( it->colour * pulseConstant ); ++it; } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 63e639ef7..fb26808b9 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -11,11 +11,37 @@ namespace MWRender{ /// information about light needed for rendering +enum LightType +{ + // These are all mutually exclusive + LT_Normal=0, + LT_Flicker=1, + LT_FlickerSlow=2, + LT_Pulse=3, + LT_PulseSlow=4 +}; + struct LightInfo { + // Constants std::string name; // ogre handle Ogre::ColourValue colour; float radius; + bool interior; // Does this light belong to an interior or exterior cell + LightType type; + + // Runtime variables + float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds + float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds + float resetTime; + long double time; + + + LightInfo() : + flickerVariation(0), resetTime(0.5), + flickerSlowVariation(0), time(0), interior(true) + { + } }; class Objects{ @@ -38,13 +64,11 @@ class Objects{ static bool lightOutQuadInLin; - bool mInterior; - void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mInterior(true) {} + Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -56,9 +80,6 @@ public: void update (const float dt); ///< per-frame update - void setInterior(const bool interior); - ///< call this to switch from interior to exterior or vice versa - Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6f6503a2e..a95a179c6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -510,13 +510,11 @@ Shadows* RenderingManager::getShadows() void RenderingManager::switchToInterior() { - mObjects.setInterior(true); mRendering.getScene()->setCameraRelativeRendering(false); } void RenderingManager::switchToExterior() { - mObjects.setInterior(false); mRendering.getScene()->setCameraRelativeRendering(true); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 803fce1e1..bcbb96eec 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -522,7 +522,6 @@ void WeatherManager::update(float duration) // re-scale to 100 percent const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; - srand(time(NULL)); float random = ((rand()%100)/100.f) * total; //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 178258a05..9e7934b15 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -17,7 +17,7 @@ struct Light { Dynamic = 0x001, Carry = 0x002, // Can be carried - Negative = 0x004, // Negative light? + Negative = 0x004, // Negative light - i.e. darkness Flicker = 0x008, Fire = 0x010, OffDefault = 0x020, // Off by default From d1d21c8a0e48ac393883376d166cf6a5f190bb6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Apr 2012 21:21:40 +0200 Subject: [PATCH 185/185] compile fix --- apps/openmw/mwrender/objects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 86a845a27..5922086a0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -365,7 +365,7 @@ void Objects::update(const float dt) // Light animation (pulse & flicker) it->time += dt; - const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20; + const float phase = std::fmod(static_cast (it->time), (32 * 2 * M_PI)) * 20; float pulseConstant; // These formulas are just guesswork, but they work pretty well