Merge remote branch 'zini/master' into sound

This commit is contained in:
Chris Robinson 2012-04-15 16:07:00 -07:00
commit 31e2447275
74 changed files with 3461 additions and 627 deletions

View file

@ -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}")
@ -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)
@ -97,6 +102,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
@ -116,6 +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})
@ -227,6 +234,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
@ -240,6 +250,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)
@ -303,11 +316,12 @@ 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}/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
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")
@ -347,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 ".")
@ -408,17 +422,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()

View file

@ -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
@ -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
@ -55,7 +55,7 @@ add_openmw_dir (mwclass
)
add_openmw_dir (mwmechanics
mechanicsmanager stat creaturestats magiceffects movement actors drawstate
mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
)
# Main executable

View file

@ -21,6 +21,7 @@
#include <components/files/fixedpath.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp>
#include <components/nifogre/ogre_nif_loader.hpp>
@ -28,6 +29,7 @@
#include "mwinput/inputmanager.hpp"
#include "mwgui/window_manager.hpp"
#include "mwgui/cursorreplace.hpp"
#include "mwscript/scriptmanager.hpp"
#include "mwscript/compilercontext.hpp"
@ -349,6 +351,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(),
@ -362,12 +371,16 @@ void OMW::Engine::go()
addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "gbuffer");
addResourcesDirectory(mResDir / "shadows");
// Create the window
mOgre->createWindow("OpenMW");
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);

View file

@ -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 },

View file

@ -53,28 +53,40 @@ 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] = (int)ref->base->npdt52.rank;
}
else
{
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]);
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);
// 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;
data->mCreatureStats.mLevel = ref->base->npdt52.level;
}
else
{
//TODO: do something with npdt12 maybe:p
}
// \todo add initial container content
@ -93,7 +105,10 @@ namespace MWClass
void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
renderingInterface.getActors().insertNPC(ptr);
renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr));
}
void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
@ -281,7 +296,7 @@ namespace MWClass
void Npc::registerSelf()
{
boost::shared_ptr<Class> instance (new Npc);
std::cout << "class npc:" << typeid (ESM::NPC).name();
registerClass (typeid (ESM::NPC).name(), instance);
}
}

View file

@ -39,6 +39,9 @@
#include "../mwscript/interpretercontext.hpp"
#include <components/compiler/scriptparser.hpp>
#include "../mwclass/npc.hpp"
#include "../mwmechanics/npcstats.hpp"
namespace
{
std::string toLower (const std::string& name)
@ -109,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 ' ':
@ -178,7 +180,17 @@ namespace MWDialogue
break;
case 46://Same faction
if(!selectCompare<int,int>(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<int,int>(comp,sameFaction,select.i)) return false;
}
break;
case 48://Detected
@ -190,7 +202,6 @@ namespace MWDialogue
break;
case 50://choice
if(choice)
{
if(!selectCompare<int,int>(comp,mChoice,select.i)) return false;
@ -270,7 +281,7 @@ namespace MWDialogue
{
case '1': // function
return true; // TODO implement functions
return true; // Done elsewhere.
case '2': // global
@ -444,9 +455,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())
{
@ -474,26 +482,37 @@ namespace MWDialogue
//NPC faction
if (!info.npcFaction.empty())
{
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>();
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<std::string,int>::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 < (int)info.data.rank) return false;
}
else
{
if(cellRef->base->npdt12.rank < info.data.rank) return false;
//not in the faction
return false;
}
}
// TODO check player faction
if(!info.pcFaction.empty())
{
MWMechanics::NpcStats stats = MWWorld::Class::get(mEnvironment.mWorld->getPlayer().getPlayer()).getNpcStats(mEnvironment.mWorld->getPlayer().getPlayer());
std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.pcFaction);
if(it!=stats.mFactionRank.end())
{
//check rank
if(it->second < (int)info.data.PCrank) return false;
}
else
{
//not in the faction
return false;
}
}
//check gender
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
@ -658,6 +677,7 @@ namespace MWDialogue
void DialogueManager::executeScript(std::string script)
{
std::cout << script;
std::vector<Interpreter::Type_Code> code;
if(compile(script,code))
{
@ -799,4 +819,19 @@ namespace MWDialogue
mChoiceMap[question] = choice;
mIsInChoice = true;
}
std::string DialogueManager::getFaction()
{
std::string factionID("");
MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor);
if(stats.mFactionRank.empty())
{
std::cout << "No faction for this actor!";
}
else
{
factionID = stats.mFactionRank.begin()->first;
}
return factionID;
}
}

View file

@ -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();

View file

@ -0,0 +1,16 @@
#include "cursorreplace.hpp"
#include <boost/filesystem.hpp>
#include <openengine/ogre/imagerotate.hpp>
#include <OgreResourceGroupManager.h>
#include <OgreRoot.h>
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);
}

View file

@ -0,0 +1,16 @@
#ifndef GAME_CURSORREPLACE_H
#define GAME_CURSORREPLACE_H
#include <string>
namespace MWGui
{
/// \brief MyGUI does not support rotating cursors, so we have to do it manually
class CursorReplace
{
public:
CursorReplace();
};
}
#endif

View file

@ -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<std::string>((int)fps));

View file

@ -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;

View file

@ -15,6 +15,8 @@
#include "journalwindow.hpp"
#include "charactercreation.hpp"
#include <components/settings/settings.hpp>
#include <assert.h>
#include <iostream>
#include <iterator>
@ -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;
}

View file

@ -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)

View file

@ -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.

View file

@ -6,6 +6,7 @@
#include "stat.hpp"
#include "magiceffects.hpp"
#include "spells.hpp"
namespace MWMechanics
{
@ -14,7 +15,7 @@ namespace MWMechanics
Stat<int> mAttributes[8];
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
int mLevel;
std::set<std::string> mAbilities;
Spells mSpells;
MagicEffects mMagicEffects;
};
}

View file

@ -1,6 +1,8 @@
#ifndef GAME_MWMECHANICS_DRAWSTATE_H
#define GAME_MWMECHANICS_DRAWSTATE_H
#undef DrawState
enum DrawState
{
DrawState_Weapon = 0,

View file

@ -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<std::string>::const_iterator iter (race->powers.list.begin());
iter!=race->powers.list.end(); ++iter)
{
insertSpell (*iter, ptr);
creatureStats.mSpells.add (*iter);
}
}
@ -85,7 +85,7 @@ namespace MWMechanics
for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
iter!=sign->powers.list.end(); ++iter)
{
insertSpell (*iter, ptr);
creatureStats.mSpells.add (*iter);
}
}
@ -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;
MagicEffects now = creatureStats.mSpells.getMagicEffects (mEnvironment);
for (std::set<std::string>::const_iterator iter (creatureStats.mAbilities.begin());
iter!=creatureStats.mAbilities.end(); ++iter)
{
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter);
for (std::vector<ESM::ENAMstruct>::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);
}
}
}
// 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);

View file

@ -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:

View file

@ -2,6 +2,7 @@
#define GAME_MWMECHANICS_NPCSTATS_H
#include <map>
#include <set>
#include "stat.hpp"
#include "drawstate.hpp"
@ -11,6 +12,10 @@ namespace MWMechanics
/// \brief Additional stats for NPCs
///
/// For non-NPC-specific stats, see the CreatureStats struct.
///
/// \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
{
// NPCs other than the player can only have one faction. But for the sake of consistency

View file

@ -0,0 +1,81 @@
#include "spells.hpp"
#include <components/esm/loadspel.hpp>
#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<ESM::ENAMstruct>::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() const
{
return mSpells.begin();
}
Spells::TIterator Spells::end() const
{
return mSpells.end();
}
void Spells::add (const std::string& spellId)
{
if (std::find (mSpells.begin(), mSpells.end(), spellId)!=mSpells.end())
mSpells.push_back (spellId);
}
void Spells::remove (const std::string& spellId)
{
TContainer::iterator iter = std::find (mSpells.begin(), mSpells.end(), spellId);
if (iter!=mSpells.end())
mSpells.erase (iter);
if (spellId==mSelectedSpell)
mSelectedSpell.clear();
}
MagicEffects Spells::getMagicEffects (const MWWorld::Environment& environment) const
{
MagicEffects 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()
{
mSpells.clear();
}
void Spells::setSelectedSpell (const std::string& spellId)
{
mSelectedSpell = spellId;
}
const std::string Spells::getSelectedSpell() const
{
return mSelectedSpell;
}
}

View file

@ -0,0 +1,66 @@
#ifndef GAME_MWMECHANICS_SPELLS_H
#define GAME_MWMECHANICS_SPELLS_H
#include <vector>
#include <string>
namespace ESM
{
struct Spell;
}
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<std::string> TContainer;
typedef TContainer::const_iterator TIterator;
private:
std::vector<std::string> mSpells;
std::string mSelectedSpell;
void addSpell (const ESM::Spell *, MagicEffects& effects) const;
public:
TIterator begin() const;
TIterator end() const;
void add (const std::string& spell);
///< 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.
};
}
#endif

View file

@ -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;
}

View file

@ -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?

View file

@ -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)
@ -305,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();
@ -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<Nif::NiKeyframeData>::iterator iter;

View file

@ -31,7 +31,7 @@ class Animation{
std::vector<std::vector<Nif::NiTriShapeCopy>* > 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<Nif::NiTriShapeCopy>* shapes; //All the NiTriShapeData for a creature
std::vector<Ogre::Entity*> entityparts;
std::vector<Nif::NiKeyframeData>* transformations;

View file

@ -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();

View file

@ -3,6 +3,7 @@
#include "renderconst.hpp"
using namespace Ogre;
using namespace NifOgre;
namespace MWRender{
@ -11,9 +12,49 @@ 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), timeToChange(0),
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),
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<ESM::NPC, MWWorld::RefData> *ref =
ptr.get<ESM::NPC>();
Ogre::Entity* blank = 0;
std::vector<Nif::NiTriShapeCopy>* 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);
rBeastFoot = std::make_pair(blank, blankshape);
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
@ -35,16 +76,21 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
std::string hairID = ref->base->hair;
std::string headID = ref->base->head;
std::string npcName = ref->base->name;
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);
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';
isFemale = 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){
@ -57,7 +103,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();
@ -66,6 +112,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
NifOgre::NIFLoader::load(smodel);
base = mRend.getScene()->createEntity(smodel);
base->setVisibilityFlags(RV_Actors);
bool transparent = false;
for (unsigned int i=0; i<base->getNumSubEntities(); ++i)
@ -87,6 +134,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
}
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
@ -105,168 +153,388 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel);
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);
std::string headModel = "meshes\\" +
mEnvironment.mWorld->getStore().bodyParts.find(headID)->model;
std::cout << "Inv" << inv.getStateId() << "\n";
updateParts();
std::string hairModel = "meshes\\" +
mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model;
const ESM::BodyPart *chest = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest");
const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg");
const ESM::BodyPart *groin = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin");
const ESM::BodyPart *arml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); //We need two
const ESM::BodyPart *neck = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck");
const ESM::BodyPart *knee = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee");
const ESM::BodyPart *ankle = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle");
const ESM::BodyPart *foot = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot");
const ESM::BodyPart *feet = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet");
const ESM::BodyPart *tail = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail");
const ESM::BodyPart *wristl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two
const ESM::BodyPart *forearml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two
const ESM::BodyPart *handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two
const ESM::BodyPart *hair = mEnvironment.mWorld->getStore().bodyParts.search(hairID);
const ESM::BodyPart *head = mEnvironment.mWorld->getStore().bodyParts.search(headID);
if(bodyRaceID == "b_n_argonian_f_")
forearml = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two
if(!handl)
handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands");
//const ESM::BodyPart* claviclel = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "clavicle");
//const ESM::BodyPart* clavicler = claviclel;
const ESM::BodyPart* handr = handl;
const ESM::BodyPart* forearmr = forearml;
const ESM::BodyPart* wristr = wristl;
const ESM::BodyPart* armr = arml;
}
void NpcAnimation::updateParts(){
bool apparelChanged = false;
if(upperleg){
insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg");
insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg");
//inv.getSlot(MWWorld::InventoryStore::Slot_Robe);
if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){
//A robe was added or removed
removePartGroup(MWWorld::InventoryStore::Slot_Robe);
robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe);
apparelChanged = true;
}
if(foot){
if(bodyRaceID.compare("b_n_khajiit_m_") == 0)
{
feet = foot;
}
else
{
insertBoundedPart("meshes\\" + foot->model, "Right Foot");
insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot");
}
if(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(groin){
insertBoundedPart("meshes\\" + groin->model, "Groin");
}
if(knee)
{
insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e
insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e
if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){
apparelChanged = true;
helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet);
removePartGroup(MWWorld::InventoryStore::Slot_Helmet);
}
if(ankle){
insertBoundedPart("meshes\\" + ankle->model + "*|", "Left Ankle"); //Ogre::Quaternion(Ogre::Radian(3.14 / 4), Ogre::Vector3(1, 0, 0)),blank); //1,0,0, blank);
insertBoundedPart("meshes\\" + ankle->model, "Right Ankle");
}
if (armr){
insertBoundedPart("meshes\\" + armr->model, "Right Upper Arm");
}
if(arml){
insertBoundedPart("meshes\\" + arml->model + "*|", "Left Upper Arm");
}
if (forearmr)
{
insertBoundedPart("meshes\\" + forearmr->model, "Right Forearm");
}
if(forearml)
insertBoundedPart("meshes\\" + forearml->model + "*|", "Left Forearm");
if (wristr)
{
insertBoundedPart("meshes\\" + wristr->model, "Right Wrist");
}
if(wristl)
insertBoundedPart("meshes\\" + wristl->model + "*|", "Left Wrist");
/*if(claviclel)
insertBoundedPart("meshes\\" + claviclel->model + "*|", "Left Clavicle", base);
if(clavicler)
insertBoundedPart("meshes\\" + clavicler->model , "Right Clavicle", base);*/
if(neck)
{
insertBoundedPart("meshes\\" + neck->model, "Neck");
}
if(head)
insertBoundedPart("meshes\\" + head->model, "Head");
if(hair)
insertBoundedPart("meshes\\" + hair->model, "Head");
if (chest){
insertFreePart("meshes\\" + chest->model, ">\"", insert);
}
if (handr){
insertFreePart("meshes\\" + handr->model , ">?", insert);
}
if (handl){
insertFreePart("meshes\\" + handl->model, ">>", insert);
}
if(tail){
insertFreePart("meshes\\" + tail->model, ">*", insert);
}
if(feet){
std::string num = getUniqueID(feet->model);
insertFreePart("meshes\\" + feet->model,"><", insert);
insertFreePart("meshes\\" + feet->model,">:", insert);
if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)){
cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass);
removePartGroup(MWWorld::InventoryStore::Slot_Cuirass);
apparelChanged = true;
}
//originalpos = insert->_getWorldAABB().getCenter();
//originalscenenode = insert->getPosition();
if(greaves != 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)){
rightpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron);
removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron);
apparelChanged = true;
}
if(!isBeast && 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);
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){
if(robe != inv.end())
{
MWWorld::Ptr ptr = *robe;
const ESM::Clothing *clothes = (ptr.get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> 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<ESM::Clothing>())->base;
std::vector<ESM::PartReference> 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()){
removeIndividualPart(ESM::PRT_Hair);
const ESM::Armor *armor = (helmet->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts);
}
if(cuirass != inv.end()){
const ESM::Armor *armor = (cuirass->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts);
}
if(greaves != inv.end()){
const ESM::Armor *armor = (greaves->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts);
}
if(leftpauldron != inv.end()){
const ESM::Armor *armor = (leftpauldron->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts);
}
if(rightpauldron != inv.end()){
const ESM::Armor *armor = (rightpauldron->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts);
}
if(!isBeast && boots != inv.end()){
if(boots->getTypeName() == typeid(ESM::Clothing).name()){
const ESM::Clothing *clothes = (boots->get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> parts = clothes->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts);
}
else if(boots->getTypeName() == typeid(ESM::Armor).name())
{
const ESM::Armor *armor = (boots->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts);
}
}
if(leftglove != inv.end()){
if(leftglove->getTypeName() == typeid(ESM::Clothing).name()){
const ESM::Clothing *clothes = (leftglove->get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> parts = clothes->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts);
}
else
{
const ESM::Armor *armor = (leftglove->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts);
}
}
if(rightglove != inv.end()){
if(rightglove->getTypeName() == typeid(ESM::Clothing).name()){
const ESM::Clothing *clothes = (rightglove->get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> parts = clothes->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts);
}
else
{
const ESM::Armor *armor = (rightglove->get<ESM::Armor>())->base;
std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts);
}
}
if(shirt != inv.end()){
const ESM::Clothing *clothes = (shirt->get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> parts = clothes->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts);
}
if(pants != inv.end()){
const ESM::Clothing *clothes = (pants->get<ESM::Clothing>())->base;
std::vector<ESM::PartReference> 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_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_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);
}
}
Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){
NIFLoader::load(mesh);
Entity* ent = mRend.getScene()->createEntity(mesh);
base->attachObjectToBone(bonename, ent);
return ent;
NIFLoader::load(mesh);
Ogre::Entity* part = mRend.getScene()->createEntity(mesh);
part->setVisibilityFlags(RV_Actors);
base->attachObjectToBone(bonename, part);
return part;
}
void NpcAnimation::insertFreePart(const std::string &mesh, const std::string suffix, Ogre::SceneNode* insert){
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> 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);
part->setVisibilityFlags(RV_Actors);
insert->attachObject(part);
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());
std::vector<Nif::NiTriShapeCopy>* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix));
if(shape){
handleShapes(shape, part, base->getSkeleton());
}
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> pair = std::make_pair(part, shape);
return pair;
}
void NpcAnimation::runAnimation(float timepassed){
if(timeToChange > .2){
timeToChange = 0;
updateParts();
}
timeToChange += timepassed;
//1. Add the amount of time passed to time
//2. Handle the animation transforms dependent on time
@ -284,23 +552,289 @@ void NpcAnimation::runAnimation(float timepassed){
time = startTime + (time - stopTime);
}
handleAnimationTransforms();
handleAnimationTransforms();
std::vector<std::vector<Nif::NiTriShapeCopy>*>::iterator shapepartsiter = shapeparts.begin();
std::vector<Ogre::Entity*>::iterator entitypartsiter = entityparts.begin();
while(shapepartsiter != shapeparts.end())
{
vecRotPos.clear();
std::vector<Nif::NiTriShapeCopy>* shapes = *shapepartsiter;
Ogre::Entity* theentity = *entitypartsiter;
handleShapes(shapes, theentity, base->getSkeleton());
shapepartsiter++;
entitypartsiter++;
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());
}
}
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(rUpperLeg);
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;
}
}
}
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){
for(int i = 0; i < 27; i++){
if(partslots[i] == group){
removeIndividualPart(i);
}
}
}
bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh){
if(priority > partpriorities[type]){
removeIndividualPart(type);
partslots[type] = group;
partpriorities[type] = priority;
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
groin = 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;
}
void NpcAnimation::addPartGroup(int group, int priority, std::vector<ESM::PartReference>& parts){
for(std::size_t 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);
else
reserveIndividualPart(part.part, group, priority);
}
}
}

View file

@ -6,24 +6,95 @@
#include <components/nif/property.hpp>
#include <components/nif/controller.hpp>
#include <components/nif/extra.hpp>
#include <utility>
#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"
#include "../mwworld/containerstore.hpp"
#include "components/esm/loadarmo.hpp"
namespace MWRender{
class NpcAnimation: public Animation{
private:
MWWorld::InventoryStore& inv;
int mStateID;
//Free Parts
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> chest;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> skirt;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> lhand;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> rhand;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> tail;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> lBeastFoot;
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> rBeastFoot;
int partslots[27]; //Each part slot is taken by clothing, armor, or is empty
int partpriorities[27];
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> zero;
//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;
Ogre::SceneNode* insert;
bool isBeast;
bool isFemale;
std::string headModel;
std::string hairModel;
std::string npcName;
std::string bodyRaceID;
float timeToChange;
MWWorld::ContainerStoreIterator robe;
MWWorld::ContainerStoreIterator helmet;
MWWorld::ContainerStoreIterator shirt;
MWWorld::ContainerStoreIterator cuirass;
MWWorld::ContainerStoreIterator greaves;
MWWorld::ContainerStoreIterator leftpauldron;
MWWorld::ContainerStoreIterator rightpauldron;
MWWorld::ContainerStoreIterator boots;
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);
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<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> insertFreePart(const std::string &mesh, const std::string suffix);
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<ESM::PartReference>& parts);
};
}

View file

@ -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);

View file

@ -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");

View file

@ -14,6 +14,10 @@
#include <components/esm/loadstat.hpp>
#include <components/settings/settings.hpp>
#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;
@ -54,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())
@ -86,6 +90,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);
@ -100,7 +110,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
RenderingManager::~RenderingManager ()
{
//TODO: destroy mSun?
delete mPlayer;
delete mSkyManager;
delete mDebugging;
@ -412,6 +421,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 +435,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)
@ -463,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()
@ -475,4 +496,9 @@ const bool RenderingManager::useMRT()
return Settings::Manager::getBool("shader", "Water");
}
Shadows* RenderingManager::getShadows()
{
return mShadows;
}
} // namespace

View file

@ -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;
};
}

View file

@ -0,0 +1,308 @@
#include "shaderhelper.hpp"
#include "renderingmanager.hpp"
#include "shadows.hpp"
#include <OgreHighLevelGpuProgramManager.h>
#include <OgreHighLevelGpuProgram.h>
#include <OgreGpuProgramParams.h>
#include <components/settings/settings.hpp>
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; i<numsplits; ++i)
{
outStream <<
" out float4 oLightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
" uniform float4x4 texViewProjMatrix"<<i<<", \n";
}
outStream <<
" uniform float4x4 worldMatrix, \n";
}
outStream <<
" 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";
if (shadows && !split) outStream <<
" oLightSpacePos0 = mul(texViewProjMatrix0, mul(worldMatrix, position)); \n";
else
{
outStream <<
" float4 wPos = mul(worldMatrix, position); \n";
for (int i=0; i<numsplits; ++i)
{
outStream <<
" oLightSpacePos"<<i<<" = mul(texViewProjMatrix"<<i<<", wPos); \n";
}
}
outStream <<
"}";
vertex->setSource(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; i<numsplits; ++i)
{
vertex->getDefaultParameters()->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<numsplits; ++i)
{
outStream <<
" uniform sampler2D shadowMap"<<i<<" : register(s"<<i+1<<"), \n"
" float4 lightSpacePos"<<i<<" : TEXCOORD"<<i+5<<", \n"
" uniform float4 invShadowmapSize"<<i<<", \n";
}
}
if (mrt) outStream <<
" out float4 oColor1 : COLOR1, \n"
" uniform float far, \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" uniform float4 lightDiffuse"<<i<<", \n"
" uniform float4 lightPositionObjSpace"<<i<<", \n"
" uniform float4 lightAttenuation"<<i<<", \n";
}
outStream <<
" uniform float4 lightAmbient, \n"
" uniform float4 ambient, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" float d; \n"
" float attn; \n"
" float3 lightDir; \n"
" float3 lightColour = float3(0, 0, 0); \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" lightDir = lightPositionObjSpace"<<i<<".xyz - (positionObjSpace.xyz * lightPositionObjSpace"<<i<<".w); \n"
// pre-multiply light color with attenuation factor
" d = length( lightDir ); \n"
" attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
" lightDiffuse"<<i<<" *= attn; \n";
if (i == 0 && shadows)
{
outStream <<
" float shadow; \n";
if (!split) outStream <<
" shadow = depthShadow(shadowMap, lightSpacePos0, invShadowmapSize0.xy); \n";
else
{
for (int j=0; j<numsplits; ++j)
{
std::string channel;
if (j==0) channel = "x";
else if (j==1) channel = "y";
else if (j==2) channel = "z";
if (j==0)
outStream << " if (iDepth <= pssmSplitPoints." << channel << ") \n";
else if (j < numsplits - 1)
outStream << " else if (iDepth <= pssmSplitPoints." << channel << ") \n";
else
outStream << " else \n";
outStream <<
" { \n"
" shadow = depthShadow(shadowMap" << j << ", lightSpacePos" << j << ", invShadowmapSize" << j << ".xy); \n"
" } \n";
}
}
outStream <<
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n"
" float fade = 1-((iDepth - shadowFar_fadeStart.y) / fadeRange); \n"
" shadow = (iDepth > 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"<<i<<".xyz;\n";
}
else outStream <<
" lightColour.xyz += lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
}
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.xyz, fogValue); \n"
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n";
if (mrt) outStream <<
" oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1
outStream <<
"}";
fragment->setSource(outStream.str());
fragment->load();
for (int i=0; i<num_lights; ++i)
{
fragment->getDefaultParameters()->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);
}
}

View file

@ -0,0 +1,29 @@
#ifndef GAME_SHADERHELPER_H
#define GAME_SHADERHELPER_H
#include <string>
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

View file

@ -0,0 +1,173 @@
#include "shadows.hpp"
#include <components/settings/settings.hpp>
#include <openengine/ogre/renderer.hpp>
#include <OgreSceneManager.h>
#include <OgreColourValue.h>
#include <OgreShadowCameraSetupLiSPSM.h>
#include <OgreShadowCameraSetupPSSM.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreOverlayContainer.h>
#include <OgreOverlayManager.h>
#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->setShadowDirectionalLightExtrusionDistance(1000000);
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<OverlayContainer*>(
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;
}

View file

@ -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

View file

@ -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);
}

View file

@ -7,7 +7,8 @@
#include "terrainmaterial.hpp"
#include "terrain.hpp"
#include "renderconst.hpp"
#include "shadows.hpp"
#include <components/settings/settings.hpp>
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);

View file

@ -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;

View file

@ -39,6 +39,8 @@ THE SOFTWARE.
#include <components/settings/settings.hpp>
#include "renderingmanager.hpp"
#undef far
namespace Ogre
{
//---------------------------------------------------------------------
@ -86,6 +88,7 @@ namespace Ogre
, mPSSM(0)
, mDepthShadows(false)
, mLowLodShadows(false)
, mShadowFar(1300)
{
}
@ -102,6 +105,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 +483,7 @@ namespace Ogre
StringUtil::StrStreamType sourceStr;
generateFragmentProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str());
ret->load();
defaultFpParams(prof, terrain, tt, ret);
@ -518,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))
{
@ -533,8 +554,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);
}
}
}
@ -554,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);
}
@ -564,9 +585,11 @@ 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))
{
params->setNamedConstant("shadowFar_fadeStart", Vector4(prof->mShadowFar, prof->mShadowFadeStart * prof->mShadowFar, 0, 0));
uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM())
{
@ -732,7 +755,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;
@ -794,7 +817,7 @@ namespace Ogre
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;
@ -814,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);
@ -831,7 +846,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__);
}
@ -921,7 +936,7 @@ namespace Ogre
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);
@ -948,8 +963,8 @@ namespace Ogre
if (fog)
{
outStream <<
"uniform float3 fogColour, \n"
"float fogVal : COLOR,\n";
"uniform float4 fogParams, \n"
"uniform float3 fogColour, \n";
}
uint currentSamplerIdx = 0;
@ -968,7 +983,7 @@ namespace Ogre
//"uniform float3 lightSpecularColour"<<i<<",\n"
;
if (prof->getNumberOfLightsSupported() > 1)
if (i > 0)
outStream <<
"uniform float4 lightAttenuation"<<i<<",\n";
@ -1137,7 +1152,7 @@ namespace Ogre
outStream << " float3 halfAngle"<<i<<" = normalize(lightDir"<<i<<" + eyeDir);\n"
" float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normal), dot(halfAngle"<<i<<", normal), scaleBiasSpecular.z);\n";
if (prof->getNumberOfLightsSupported() > 1)
if (i > 0)
outStream <<
// pre-multiply light color with attenuation factor
"d = length( lightDir"<<i<<" ); \n"
@ -1249,22 +1264,7 @@ namespace Ogre
outStream <<
" // pass cam depth\n"
" oUVMisc.z = oPos.z;\n";
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog)
{
if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
{
outStream <<
" fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
}
else
{
outStream <<
" fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n";
}
}
" oPosObj.w = oPos.z;\n";
if (prof->isShadowingEnabled(tt, terrain))
generateVpDynamicShadows(prof, terrain, tt, outStream);
@ -1315,7 +1315,13 @@ namespace Ogre
// diffuse lighting
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{
// shadows only for first light (directional)
if (i==0)
outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse * shadow;\n";
else
outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse;\n";
}
// specular default
if (!prof->isLayerSpecularMappingEnabled())
@ -1343,6 +1349,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";
}
@ -1350,7 +1366,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";
@ -1364,7 +1380,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 +1393,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 +1442,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 +1464,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 +1526,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 +1544,8 @@ namespace Ogre
// in semantics & params
uint numTextures = 1;
outStream <<
", uniform float4 shadowFar_fadeStart \n";
if (prof->getReceiveDynamicShadowsPSSM())
{
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
@ -1554,7 +1562,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
", uniform float inverseShadowmapSize" << i << " \n";
", uniform float4 inverseShadowmapSize" << i << " \n";
}
}
@ -1567,7 +1575,7 @@ namespace Ogre
{
uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
outStream <<
" float camDepth = uvMisc.z;\n";
" float camDepth = position.w;\n";
if (prof->getReceiveDynamicShadowsDepth())
{
@ -1589,7 +1597,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 +1608,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth())
{
outStream <<
" float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);";
" float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0.xy);";
}
else
{
@ -1609,7 +1617,11 @@ namespace Ogre
}
}
outStream <<
outStream <<
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \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";
}

View file

@ -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;

View file

@ -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;
@ -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,13 +80,61 @@ 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<OverlayContainer*>(
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)
{
mActive = active;
if (mReflectionTarget) mReflectionTarget->setActive(active && !mIsUnderwater);
mWater->setVisible(active);
updateVisible();
}
Water::~Water()
@ -112,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)
@ -128,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)
{
@ -146,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)
@ -164,7 +214,12 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
{
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
@ -174,21 +229,19 @@ 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));
}
}
void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
{
mWater->setVisible(true);
if (evt.source == mReflectionTarget)
{
mSky->resetSkyPosition();
mSky->scaleSky(1);
mCamera->disableReflection();
mCamera->disableCustomNearClipPlane();
mReflectionCamera->disableCustomNearClipPlane();
mReflectionCamera->disableReflection();
}
}
@ -230,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

View file

@ -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;
@ -39,6 +41,8 @@ namespace MWRender {
void createMaterial();
Ogre::MaterialPtr mMaterial;
Ogre::Camera* mReflectionCamera;
Ogre::RenderTarget* mReflectionTarget;
bool mUnderwaterEffect;

View file

@ -11,6 +11,7 @@
#include "../mwdialogue/dialoguemanager.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
namespace MWScript
{
@ -115,12 +116,27 @@ namespace MWScript
}
};
template<class R>
class OpForceGreeting : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (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;
const int opcodeForceGreetingExplicit = 0x2000150;
void registerExtensions (Compiler::Extensions& extensions)
{
@ -129,6 +145,9 @@ namespace MWScript
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting);
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
opcodeForceGreetingExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -138,6 +157,8 @@ namespace MWScript
interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex);
interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic);
interpreter.installSegment3 (opcodeChoice,new OpChoice);
interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting<ImplicitRef>);
interpreter.installSegment5 (opcodeForceGreetingExplicit, new OpForceGreeting<ExplicitRef>);
}
}

View file

@ -24,7 +24,12 @@ op 0x20007: PlayAnim, explicit reference
op 0x20008: LoopAnim
op 0x20009: LoopAnim, explicit reference
op 0x2000a: Choice
opcodes 0x2000b-0x3ffff unused
op 0x2000b: PCRaiseRank
op 0x2000c: PCLowerRank
op 0x2000d: PCJoinFaction
op 0x2000e: PCGetRank implicit
op 0x2000f: PCGetRank explicit
opcodes 0x20010-0x3ffff unused
Segment 4:
(not implemented yet)
@ -129,4 +134,14 @@ 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
op 0x200014b: GetSpell
op 0x200014c: GetSpell, explicit reference
op 0x200014d: ModDisposition
op 0x200014e: ModDisposition, explicit reference
op 0x200014f: ForceGreeting
op 0x2000150: ForceGreeting, explicit reference
opcodes 0x2000151-0x3ffffff unused

View file

@ -8,6 +8,8 @@
#include <components/interpreter/opcodes.hpp>
#include "../mwworld/class.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -15,6 +17,8 @@
#include "interpretercontext.hpp"
#include "ref.hpp"
#include "../mwdialogue/dialoguemanager.hpp"
namespace MWScript
{
namespace Stats
@ -280,6 +284,220 @@ namespace MWScript
}
};
template<class R>
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 R>
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);
}
};
template<class R>
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);
}
};
class OpPCJoinFaction : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
std::string factionID = "";
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (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())
{
MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0;
}
}
}
};
class OpPCRaiseRank : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
std::string factionID = "";
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (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())
{
MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0;
}
else
{
MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] +1;
}
}
}
};
class OpPCLowerRank : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
std::string factionID = "";
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (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())
{
MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] -1;
}
}
}
};
template<class R>
class OpGetPCRank : public Interpreter::Opcode1
{
public:
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
{
MWWorld::Ptr ptr = R()(runtime);
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<MWScript::InterpreterContext&> (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 R>
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
}
};
const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027;
@ -311,6 +529,21 @@ 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;
const int opcodeGetSpell = 0x200014b;
const int opcodeGetSpellExplicit = 0x200014c;
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;
void registerExtensions (Compiler::Extensions& extensions)
{
static const char *attributes[numberOfAttributes] =
@ -381,6 +614,18 @@ namespace MWScript
extensions.registerInstruction (mod + skills[i], "l",
opcodeModSkill+i, opcodeModSkillExplicit+i);
}
extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit);
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
opcodeRemoveSpellExplicit);
extensions.registerFunction ("getspell", 'l', "c", opcodeGetSpell, opcodeGetSpellExplicit);
extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank);
extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank);
extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction);
extensions.registerInstruction("moddisposition","l",opcodeModDisposition,
opcodeModDispositionExplicit);
extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
@ -436,6 +681,22 @@ namespace MWScript
interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill<ImplicitRef> (i));
interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill<ExplicitRef> (i));
}
interpreter.installSegment5 (opcodeAddSpell, new OpAddSpell<ImplicitRef>);
interpreter.installSegment5 (opcodeAddSpellExplicit, new OpAddSpell<ExplicitRef>);
interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell<ImplicitRef>);
interpreter.installSegment5 (opcodeRemoveSpellExplicit,
new OpRemoveSpell<ExplicitRef>);
interpreter.installSegment5 (opcodeGetSpell, new OpGetSpell<ImplicitRef>);
interpreter.installSegment5 (opcodeGetSpellExplicit, new OpGetSpell<ExplicitRef>);
interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank);
interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank);
interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction);
interpreter.installSegment5(opcodeModDisposition,new OpModDisposition<ImplicitRef>);
interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition<ExplicitRef>);
interpreter.installSegment3(opcodeGetPCRank,new OpGetPCRank<ImplicitRef>);
interpreter.installSegment3(opcodeGetPCRankExplicit,new OpGetPCRank<ExplicitRef>);
}
}
}

View file

@ -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();

View file

@ -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)
{
// Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
}
PhysicsSystem::~PhysicsSystem()
@ -90,55 +93,78 @@ 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<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{
OEngine::Physic::PhysicActor* act = it->second;
act->setWalkDirection(btVector3(0,0,0));
}
//playerphysics->ps.move_type = PM_NOCLIP;
for (std::vector<std::pair<std::string, Ogre::Vector3> >::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.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);
//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);
dir = 0.025*(quat*dir1);
}
//set the walk direction
act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y));
}
mEngine->stepSimulation(duration);
std::vector< std::pair<std::string, Ogre::Vector3> > response;
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{
btVector3 newPos = it->second->getPosition();
Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z());
response.push_back(std::pair<std::string, Ogre::Vector3>(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)
{

View file

@ -54,6 +54,7 @@ namespace MWWorld
OEngine::Physic::PhysicEngine* mEngine;
bool mFreeFly;
PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&);
};

69
cmake/FindFreetype.cmake Normal file
View file

@ -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")

View file

@ -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 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)
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}")

View file

@ -6,6 +6,10 @@ add_component_dir (settings
settings
)
add_component_dir (nifoverrides
nifoverrides
)
add_component_dir (bsa
bsa_archive bsa_file
)

View file

@ -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());

View file

@ -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);
}
}

View file

@ -13,6 +13,7 @@ void Clothing::load(ESMReader &esm)
icon = esm.getHNOString("ITEX");
parts.load(esm);
enchant = esm.getHNOString("ENAM");
}

View file

@ -26,6 +26,7 @@
#include "ogre_nif_loader.hpp"
#include <components/settings/settings.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
typedef unsigned char ubyte;
@ -282,15 +283,61 @@ 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);
}
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 +346,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; i<num_lights; ++i)
{
outStream <<
" uniform float4 lightDiffuse"<<i<<", \n"
" uniform float4 lightPositionObjSpace"<<i<<", \n"
" uniform float4 lightAttenuation"<<i<<", \n";
}
outStream <<
" uniform float4 lightAmbient, \n"
" uniform float4 ambient, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" float d; \n"
" float attn; \n"
" float3 lightColour = float3(0, 0, 0); \n";
for (int i=0; i<num_lights; ++i)
{
outStream <<
" float3 lightDir"<<i<<" = lightPositionObjSpace"<<i<<".xyz - (positionObjSpace.xyz * lightPositionObjSpace"<<i<<".w); \n"
// pre-multiply light color with attenuation factor
" d = length( lightDir"<<i<<" ); \n"
" attn = ( 1.0 / (( lightAttenuation"<<i<<".y ) + ( lightAttenuation"<<i<<".z * d ) + ( lightAttenuation"<<i<<".w * d * d ))); \n"
" lightDiffuse"<<i<<" *= attn; \n"
" lightColour.xyz += lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), 0, 0).y * lightDiffuse"<<i<<".xyz;\n";
}
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.a = tex.a * diffuse.a * vertexColour.a; \n";
if (mrt) outStream <<
" oColor1 = float4(iDepth / far, 0, 0, (oColor.a == 1)); \n"; // only write to MRT if alpha is 1
outStream <<
"}";
fragment->setSource(outStream.str());
fragment->load();
for (int i=0; i<num_lights; ++i)
{
fragment->getDefaultParameters()->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
@ -1309,6 +1211,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")
@ -1339,6 +1242,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))
{
@ -1477,7 +1391,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);
}
}

View file

@ -0,0 +1,37 @@
#include "nifoverrides.hpp"
#include <OgreStringConverter.h>
#include <boost/algorithm/string.hpp>
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;
}

View file

@ -0,0 +1,23 @@
#ifndef COMPONENTS_NIFOVERRIDES_H
#define COMPONENTS_NIFOVERRIDES_H
#include <OgreConfigFile.h>
namespace NifOverrides
{
typedef std::pair<bool, int> 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

View file

@ -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)

View file

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -2,37 +2,37 @@
<MyGUI type="Resource">
<Resource type="ResourceImageSet" name="ArrowPointerImage">
<Group name="Pointer" texture="mwpointer.png" size="32 32">
<Group name="Pointer" texture="textures\tx_cursor.dds" size="32 32">
<Index name="Pointer" >
<Frame point="0 0"/>
</Index>
</Group>
</Resource>
<Resource type="ResourceImageSet" name="HResizePointerImage">
<Group name="Pointer" texture="mwpointer.png" size="32 32">
<Group name="Pointer" texture="textures\tx_cursormove.dds" size="32 32">
<Index name="Pointer" >
<Frame point="32 0"/>
<Frame point="0 0"/>
</Index>
</Group>
</Resource>
<Resource type="ResourceImageSet" name="VResizePointerImage">
<Group name="Pointer" texture="mwpointer.png" size="32 32">
<Group name="Pointer" texture="mwpointer_vresize.png" size="32 32">
<Index name="Pointer" >
<Frame point="0 32"/>
<Frame point="0 0"/>
</Index>
</Group>
</Resource>
<Resource type="ResourceImageSet" name="DResizePointerImage">
<Group name="Pointer" texture="mwpointer.png" size="32 32">
<Group name="Pointer" texture="mwpointer_dresize1.png" size="32 32">
<Index name="Pointer" >
<Frame point="32 32"/>
<Frame point="o o"/>
</Index>
</Group>
</Resource>
<Resource type="ResourceImageSet" name="DResize2PointerImage">
<Group name="Pointer" texture="mwpointer.png" size="32 32">
<Group name="Pointer" texture="mwpointer_dresize2.png" size="32 32">
<Index name="Pointer" >
<Frame point="64 32"/>
<Frame point="0 0"/>
</Index>
</Group>
</Resource>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Resource" version="1.1">
<Resource type="ResourceSkin" name="Skin name 0" size="32 32" texture="">
<BasisSkin type="SubSkin" offset="0 0 32 32" align="Stretch">
<State name="normal" offset="0 0 32 32"/>
</BasisSkin>
</Resource>
</MyGUI>

View file

@ -1,5 +1,5 @@
[Desktop Entry]
Version=0.11
Version=${OPENMW_VERSION}
Type=Application
Name=OpenMW Launcher
GenericName=Role Playing Game

View file

@ -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 actors = false
reflect misc = false
# Enable underwater effect. It is not resource intensive, so only disable it if you have problems.

View file

@ -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);
}

View file

@ -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
{
}
}
}
}

View file

@ -0,0 +1,574 @@
# 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
# fauna
[textures\tx_wickwheat_01.dds]
alphaRejectValue = 128
[textures\tx_wickwheat_03.dds]
alphaRejectValue = 128
[textures\tx_red_lichen_01.dds]
alphaRejectValue = 128
[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]
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_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
[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_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_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

View file

@ -92,7 +92,7 @@ material Water
}
technique
{
scheme Map
scheme Fallback
pass
{
cull_hardware none

View file

@ -0,0 +1,62 @@
#ifndef OENGINE_BULLET_TRACE_H
#define OENGINE_BULLET_TRACE_H
#include <btBulletDynamicsCommon.h>
#include <btBulletCollisionCommon.h>
#include <components/nifbullet/bullet_nif_loader.hpp>
//#include <apps\openmw\mwworld\world.hpp>
#include <openengine/bullet/pmove.h>
#include <openengine/bullet/physic.hpp>
enum traceWorldType
{
collisionWorldTrace = 1,
pickWorldTrace = 2,
bothWorldTrace = collisionWorldTrace | pickWorldTrace
};
enum collaborativePhysicsType : unsigned
{
No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass)
Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics)
Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground)
Both_Physics = 3 // This object has both kinds of physics (example: activators)
};
struct NewPhysTraceResults
{
Ogre::Vector3 endPos;
Ogre::Vector3 hitNormal;
float fraction;
bool startSolid;
//const Object* hitObj;
};
struct traceResults
{
Ogre::Vector3 endpos;
Ogre::Vector3 planenormal;
float fraction;
int surfaceFlags;
int contents;
int entityNum;
bool allsolid;
bool startsolid;
};
template <const traceWorldType traceType>
const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
template const bool NewPhysicsTrace<collisionWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
template const bool NewPhysicsTrace<pickWorldTrace>(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass);
#endif

View file

@ -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();

View file

@ -0,0 +1,74 @@
#include "imagerotate.hpp"
#include <OgreRoot.h>
#include <OgreSceneManager.h>
#include <OgreImage.h>
#include <OgreTexture.h>
#include <OgreRenderTarget.h>
#include <OgreCamera.h>
#include <OgreTextureUnitState.h>
#include <OgreHardwarePixelBuffer.h>
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(
destImage,
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
TEX_TYPE_2D,
width, height,
0,
PF_A8R8G8B8,
TU_RENDERTARGET);
RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget();
rtt->setAutoUpdated(false);
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();
// remove all the junk we've created
MaterialManager::getSingleton().remove("ImageRotateMaterial");
root->destroySceneManager(sceneMgr);
delete rect;
}

View file

@ -0,0 +1,27 @@
#ifndef OENGINE_OGRE_IMAGEROTATE_HPP
#define OENGINE_OGRE_IMAGEROTATE_HPP
#include <string>
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 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);
};
}
}
#endif

View file

@ -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,11 +88,13 @@ 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
Current Developers:
Aleksandar Jovanov
Alexander “Ace” Olofsson
athile
BrotherBrick
@ -133,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