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 # Version
set (OPENMW_VERSION_MAJOR 0) set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 13) set (OPENMW_VERSION_MINOR 14)
set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") 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(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) 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 # Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF)
option(USE_AUDIERE "use audiere 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/renderer.cpp
${LIBDIR}/openengine/ogre/mouselook.cpp ${LIBDIR}/openengine/ogre/mouselook.cpp
${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
) )
set(OENGINE_GUI set(OENGINE_GUI
${LIBDIR}/openengine/gui/events.cpp ${LIBDIR}/openengine/gui/events.cpp
@ -116,6 +122,7 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.h ${LIBDIR}/openengine/bullet/BulletShapeLoader.h
) )
set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET})
@ -227,6 +234,9 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/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 configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg") "${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
@ -240,6 +250,9 @@ endif (WIN32)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux
"${OpenMW_BINARY_DIR}/plugins.cfg") "${OpenMW_BINARY_DIR}/plugins.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop
"${OpenMW_BINARY_DIR}/openmw.desktop")
endif() endif()
if (APPLE) if (APPLE)
@ -303,11 +316,12 @@ if(DPKG_PROGRAM)
endif() endif()
#Install icon and desktop file #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(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 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}/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}/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") INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
@ -408,17 +422,14 @@ add_subdirectory (components)
# Apps and tools # Apps and tools
add_subdirectory( apps/openmw ) add_subdirectory( apps/openmw )
option(BUILD_ESMTOOL "build ESM inspector" ON)
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
add_subdirectory( apps/esmtool ) add_subdirectory( apps/esmtool )
endif() endif()
option(BUILD_LAUNCHER "build Launcher inspector" ON)
if (BUILD_LAUNCHER) if (BUILD_LAUNCHER)
add_subdirectory( apps/launcher ) add_subdirectory( apps/launcher )
endif() endif()
option(BUILD_MWINIIMPORTER "build MWiniImporter inspector" ON)
if (BUILD_MWINIIMPORTER) if (BUILD_MWINIIMPORTER)
add_subdirectory( apps/mwiniimporter ) add_subdirectory( apps/mwiniimporter )
endif() endif()

View file

@ -15,7 +15,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects 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 add_openmw_dir (mwinput
@ -25,7 +25,7 @@ add_openmw_dir (mwinput
add_openmw_dir (mwgui add_openmw_dir (mwgui
layouts text_input widgets race class birth review window_manager console dialogue layouts text_input widgets race class birth review window_manager console dialogue
dialogue_history window_base stats_window messagebox journalwindow charactercreation dialogue_history window_base stats_window messagebox journalwindow charactercreation
map_window window_pinnable_base map_window window_pinnable_base cursorreplace
) )
add_openmw_dir (mwdialogue add_openmw_dir (mwdialogue
@ -55,7 +55,7 @@ add_openmw_dir (mwclass
) )
add_openmw_dir (mwmechanics add_openmw_dir (mwmechanics
mechanicsmanager stat creaturestats magiceffects movement actors drawstate mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
) )
# Main executable # Main executable

View file

@ -21,6 +21,7 @@
#include <components/files/fixedpath.hpp> #include <components/files/fixedpath.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
#include <components/nifbullet/bullet_nif_loader.hpp> #include <components/nifbullet/bullet_nif_loader.hpp>
#include <components/nifogre/ogre_nif_loader.hpp> #include <components/nifogre/ogre_nif_loader.hpp>
@ -28,6 +29,7 @@
#include "mwinput/inputmanager.hpp" #include "mwinput/inputmanager.hpp"
#include "mwgui/window_manager.hpp" #include "mwgui/window_manager.hpp"
#include "mwgui/cursorreplace.hpp"
#include "mwscript/scriptmanager.hpp" #include "mwscript/scriptmanager.hpp"
#include "mwscript/compilercontext.hpp" #include "mwscript/compilercontext.hpp"
@ -349,6 +351,13 @@ void OMW::Engine::go()
mFpsLevel = settings.getInt("fps", "HUD"); 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()), mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
mCfgMgr.getOgreConfigPath().string(), mCfgMgr.getOgreConfigPath().string(),
mCfgMgr.getLogPath().string(), mCfgMgr.getLogPath().string(),
@ -362,12 +371,16 @@ void OMW::Engine::go()
addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "water");
addResourcesDirectory(mResDir / "gbuffer"); addResourcesDirectory(mResDir / "gbuffer");
addResourcesDirectory(mResDir / "shadows");
// Create the window // Create the window
mOgre->createWindow("OpenMW"); mOgre->createWindow("OpenMW");
loadBSA(); loadBSA();
// cursor replacer (converts the cursor from the bsa so they can be used by mygui)
MWGui::CursorReplace replacer;
// Create the world // Create the world
mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster, mEnvironment.mWorld = new MWWorld::World (*mOgre, mFileCollections, mMaster,
mResDir, mNewGame, mEnvironment, mEncoding, mFallbackMap); mResDir, mNewGame, mEnvironment, mEncoding, mFallbackMap);

View file

@ -89,7 +89,7 @@ namespace MWClass
static const int sMapping[size][2] = 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::Belt, MWWorld::InventoryStore::Slot_Belt },
{ ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe }, { ESM::Clothing::Robe, MWWorld::InventoryStore::Slot_Robe },
{ ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants }, { ESM::Clothing::Pants, MWWorld::InventoryStore::Slot_Pants },

View file

@ -53,11 +53,18 @@ namespace MWClass
// NPC stats // NPC stats
if (!ref->base->faction.empty()) if (!ref->base->faction.empty())
{ {
// TODO research how initial rank is stored. The information in loadnpc.hpp are at if(ref->base->npdt52.gold != -10)
// best very unclear. {
data->mNpcStats.mFactionRank[ref->base->faction] = 0; data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank;
}
else
{
data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank;
}
} }
if(ref->base->npdt52.gold != -10)
{
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);
@ -75,6 +82,11 @@ namespace MWClass
data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue); 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 // \todo add initial container content
@ -93,7 +105,10 @@ namespace MWClass
void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const 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 void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
@ -281,7 +296,7 @@ namespace MWClass
void Npc::registerSelf() void Npc::registerSelf()
{ {
boost::shared_ptr<Class> instance (new Npc); boost::shared_ptr<Class> instance (new Npc);
std::cout << "class npc:" << typeid (ESM::NPC).name();
registerClass (typeid (ESM::NPC).name(), instance); registerClass (typeid (ESM::NPC).name(), instance);
} }
} }

View file

@ -39,6 +39,9 @@
#include "../mwscript/interpretercontext.hpp" #include "../mwscript/interpretercontext.hpp"
#include <components/compiler/scriptparser.hpp> #include <components/compiler/scriptparser.hpp>
#include "../mwclass/npc.hpp"
#include "../mwmechanics/npcstats.hpp"
namespace namespace
{ {
std::string toLower (const std::string& name) std::string toLower (const std::string& name)
@ -109,16 +112,15 @@ namespace
switch (world.getGlobalVariableType (name)) switch (world.getGlobalVariableType (name))
{ {
case 's': case 's':
return selectCompare (comp, world.getGlobalVariable (name).mShort, value);
return selectCompare (comp, value, world.getGlobalVariable (name).mShort);
case 'l': case 'l':
return selectCompare (comp, value, world.getGlobalVariable (name).mLong); return selectCompare (comp, world.getGlobalVariable (name).mLong, value);
case 'f': case 'f':
return selectCompare (comp, value, world.getGlobalVariable (name).mFloat); return selectCompare (comp, world.getGlobalVariable (name).mFloat, value);
case ' ': case ' ':
@ -178,7 +180,17 @@ namespace MWDialogue
break; break;
case 46://Same faction 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; break;
case 48://Detected case 48://Detected
@ -190,7 +202,6 @@ namespace MWDialogue
break; break;
case 50://choice case 50://choice
if(choice) if(choice)
{ {
if(!selectCompare<int,int>(comp,mChoice,select.i)) return false; if(!selectCompare<int,int>(comp,mChoice,select.i)) return false;
@ -270,7 +281,7 @@ namespace MWDialogue
{ {
case '1': // function case '1': // function
return true; // TODO implement functions return true; // Done elsewhere.
case '2': // global case '2': // global
@ -444,9 +455,6 @@ namespace MWDialogue
if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor)) if (toLower (info.actor)!=MWWorld::Class::get (actor).getId (actor))
return false; return false;
//PC Faction
if(!info.pcFaction.empty()) return false;
//NPC race //NPC race
if (!info.race.empty()) if (!info.race.empty())
{ {
@ -474,26 +482,37 @@ namespace MWDialogue
//NPC faction //NPC faction
if (!info.npcFaction.empty()) if (!info.npcFaction.empty())
{ {
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *cellRef = actor.get<ESM::NPC>(); //MWWorld::Class npcClass = MWWorld::Class::get(actor);
MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor);
if (!cellRef) std::map<std::string,int>::iterator it = stats.mFactionRank.find(info.npcFaction);
return false; if(it!=stats.mFactionRank.end())
if (toLower (info.npcFaction)!=toLower (cellRef->base->faction))
return false;
//check NPC rank
if(cellRef->base->npdt52.gold != -10)
{ {
if(cellRef->base->npdt52.rank < info.data.rank) return false; //check rank
if(it->second < (int)info.data.rank) return false;
} }
else else
{ {
if(cellRef->base->npdt12.rank < info.data.rank) return false; //not in the faction
return false;
} }
} }
// TODO check player faction // 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 //check gender
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>(); ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData>* npc = actor.get<ESM::NPC>();
@ -658,6 +677,7 @@ namespace MWDialogue
void DialogueManager::executeScript(std::string script) void DialogueManager::executeScript(std::string script)
{ {
std::cout << script;
std::vector<Interpreter::Type_Code> code; std::vector<Interpreter::Type_Code> code;
if(compile(script,code)) if(compile(script,code))
{ {
@ -799,4 +819,19 @@ namespace MWDialogue
mChoiceMap[question] = choice; mChoiceMap[question] = choice;
mIsInChoice = true; 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); void askQuestion(std::string question,int choice);
///get the faction of the actor you are talking with
std::string getFaction();
//calbacks for the GUI //calbacks for the GUI
void keywordSelected(std::string keyword); void keywordSelected(std::string keyword);
void goodbyeSelected(); 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"); getWidget(crosshair, "Crosshair");
if ( fpsLevel == 2 ){ setFpsLevel(fpsLevel);
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");
}
getWidget(trianglecounter, "TriangleCounter"); getWidget(trianglecounter, "TriangleCounter");
getWidget(batchcounter, "BatchCounter"); getWidget(batchcounter, "BatchCounter");
@ -95,6 +86,28 @@ HUD::HUD(int width, int height, int fpsLevel)
LocalMapBase::init(minimap, this); 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) void HUD::setFPS(float fps)
{ {
fpscounter->setCaption(boost::lexical_cast<std::string>((int)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 setPlayerPos(const float x, const float y);
void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible);
void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible);
void setFpsLevel(const int level);
MyGUI::ProgressPtr health, magicka, stamina; MyGUI::ProgressPtr health, magicka, stamina;
MyGUI::Widget *weapBox, *spellBox; MyGUI::Widget *weapBox, *spellBox;

View file

@ -15,6 +15,8 @@
#include "journalwindow.hpp" #include "journalwindow.hpp"
#include "charactercreation.hpp" #include "charactercreation.hpp"
#include <components/settings/settings.hpp>
#include <assert.h> #include <assert.h>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
@ -472,3 +474,11 @@ void WindowManager::toggleFogOfWar()
map->toggleFogOfWar(); map->toggleFogOfWar();
hud->toggleFogOfWar(); hud->toggleFogOfWar();
} }
int WindowManager::toggleFps()
{
showFPSLevel = (showFPSLevel+1)%3;
hud->setFpsLevel(showFPSLevel);
Settings::Manager::setInt("fps", "HUD", showFPSLevel);
return showFPSLevel;
}

View file

@ -159,6 +159,9 @@ namespace MWGui
void toggleFogOfWar(); void toggleFogOfWar();
int toggleFps();
///< toggle fps display @return resulting fps level
void setInteriorMapTexture(const int x, const int y); void setInteriorMapTexture(const int x, const int y);
///< set the index of the map texture that should be used (for interiors) ///< set the index of the map texture that should be used (for interiors)

View file

@ -68,6 +68,8 @@ namespace MWInput
A_ToggleWeapon, A_ToggleWeapon,
A_ToggleSpell, A_ToggleSpell,
A_ToggleFps, // Toggle FPS display (this is temporary)
A_LAST // Marker for the last item A_LAST // Marker for the last item
}; };
@ -88,6 +90,11 @@ namespace MWInput
/* InputImpl Methods */ /* InputImpl Methods */
void toggleFps()
{
windows.toggleFps();
}
void toggleSpell() void toggleSpell()
{ {
DrawState state = player.getDrawState(); DrawState state = player.getDrawState();
@ -235,6 +242,8 @@ namespace MWInput
"Draw Weapon"); "Draw Weapon");
disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this),
"Ready hands"); "Ready hands");
disp->funcs.bind(A_ToggleFps, boost::bind(&InputImpl::toggleFps, this),
"Toggle FPS display");
// Add the exit listener // Add the exit listener
ogre.getRoot()->addFrameListener(&exit); ogre.getRoot()->addFrameListener(&exit);
@ -281,6 +290,7 @@ namespace MWInput
disp->bind(A_ToggleWalk, KC_C); disp->bind(A_ToggleWalk, KC_C);
disp->bind(A_ToggleWeapon,KC_F); disp->bind(A_ToggleWeapon,KC_F);
disp->bind(A_ToggleSpell,KC_R); disp->bind(A_ToggleSpell,KC_R);
disp->bind(A_ToggleFps, KC_F10);
// Key bindings for polled keys // Key bindings for polled keys
// NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. // 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 "stat.hpp"
#include "magiceffects.hpp" #include "magiceffects.hpp"
#include "spells.hpp"
namespace MWMechanics namespace MWMechanics
{ {
@ -14,7 +15,7 @@ namespace MWMechanics
Stat<int> mAttributes[8]; Stat<int> mAttributes[8];
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
int mLevel; int mLevel;
std::set<std::string> mAbilities; Spells mSpells;
MagicEffects mMagicEffects; MagicEffects mMagicEffects;
}; };
} }

View file

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

View file

@ -23,7 +23,7 @@ namespace MWMechanics
// reset // reset
creatureStats.mLevel = player->npdt52.level; creatureStats.mLevel = player->npdt52.level;
creatureStats.mAbilities.clear(); creatureStats.mSpells.clear();
creatureStats.mMagicEffects = MagicEffects(); creatureStats.mMagicEffects = MagicEffects();
for (int i=0; i<27; ++i) 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()); for (std::vector<std::string>::const_iterator iter (race->powers.list.begin());
iter!=race->powers.list.end(); ++iter) 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()); for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
iter!=sign->powers.list.end(); ++iter) 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()); 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) void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
{ {
MWMechanics::CreatureStats& creatureStats = MWMechanics::CreatureStats& creatureStats =
MWWorld::Class::get (creature).getCreatureStats (creature); 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()); /// \todo add effects from active spells and equipment
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
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); 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 ///< 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. /// 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); void adjustMagicEffects (MWWorld::Ptr& creature);
public: public:

View file

@ -2,6 +2,7 @@
#define GAME_MWMECHANICS_NPCSTATS_H #define GAME_MWMECHANICS_NPCSTATS_H
#include <map> #include <map>
#include <set>
#include "stat.hpp" #include "stat.hpp"
#include "drawstate.hpp" #include "drawstate.hpp"
@ -11,6 +12,10 @@ namespace MWMechanics
/// \brief Additional stats for NPCs /// \brief Additional stats for NPCs
/// ///
/// For non-NPC-specific stats, see the CreatureStats struct. /// 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 struct NpcStats
{ {
// NPCs other than the player can only have one faction. But for the sake of consistency // 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){ void Actors::setMwRoot(Ogre::SceneNode* root){
mMwRoot = root; mMwRoot = root;
} }
void Actors::insertNPC(const MWWorld::Ptr& ptr){ void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){
insertBegin(ptr, true, true); insertBegin(ptr, true, true);
NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend); NpcAnimation* anim = new MWRender::NpcAnimation(ptr, mEnvironment, mRend, inv);
mAllActors[ptr] = anim; mAllActors[ptr] = anim;
} }

View file

@ -34,7 +34,7 @@ namespace MWRender{
void setMwRoot(Ogre::SceneNode* root); void setMwRoot(Ogre::SceneNode* root);
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertCreature (const MWWorld::Ptr& ptr); 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); bool deleteObject (const MWWorld::Ptr& ptr);
///< \return found? ///< \return found?

View file

@ -9,7 +9,6 @@ namespace MWRender{
, mRend(_rend) , mRend(_rend)
, mEnvironment(_env) , mEnvironment(_env)
, vecRotPos() , vecRotPos()
, shapeparts()
, time(0.0f) , time(0.0f)
, startTime(0.0f) , startTime(0.0f)
, stopTime(0.0f) , stopTime(0.0f)
@ -19,7 +18,6 @@ namespace MWRender{
, shapeNumber(0) , shapeNumber(0)
, shapeIndexI() , shapeIndexI()
, shapes(NULL) , shapes(NULL)
, entityparts()
, transformations(NULL) , transformations(NULL)
, textmappings(NULL) , textmappings(NULL)
, base(NULL) , base(NULL)
@ -305,8 +303,8 @@ namespace MWRender{
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++) for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
{ {
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){ if(skel->hasBone(*boneSequenceIter)){
Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(*boneSequenceIter); Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter);
// Computes C = B + AxC*scale // Computes C = B + AxC*scale
transmult = transmult + rotmult * bonePtr->getPosition(); transmult = transmult + rotmult * bonePtr->getPosition();
rotmult = rotmult * bonePtr->getOrientation(); rotmult = rotmult * bonePtr->getOrientation();
@ -430,14 +428,7 @@ namespace MWRender{
//base->_updateAnimation(); //base->_updateAnimation();
//base->_notifyMoved(); //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; 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 time;
float startTime; float startTime;
@ -48,7 +48,7 @@ class Animation{
//Ogre::SkeletonInstance* skel; //Ogre::SkeletonInstance* skel;
std::vector<Nif::NiTriShapeCopy>* shapes; //All the NiTriShapeData for a creature std::vector<Nif::NiTriShapeCopy>* shapes; //All the NiTriShapeData for a creature
std::vector<Ogre::Entity*> entityparts;
std::vector<Nif::NiKeyframeData>* transformations; std::vector<Nif::NiKeyframeData>* transformations;

View file

@ -225,7 +225,9 @@ void LocalMap::render(const float x, const float y,
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setBackgroundColour(ColourValue(0, 0, 0));
vp->setVisibilityMask(RV_Map); vp->setVisibilityMask(RV_Map);
vp->setMaterialScheme("Map");
// use fallback techniques without shadows and without mrt
vp->setMaterialScheme("Fallback");
rtt->update(); rtt->update();

View file

@ -3,6 +3,7 @@
#include "renderconst.hpp" #include "renderconst.hpp"
using namespace Ogre; using namespace Ogre;
using namespace NifOgre; using namespace NifOgre;
namespace MWRender{ 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 = ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
ptr.get<ESM::NPC>(); 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 //Part selection on last character of the file string
// " Tri Chest // " Tri Chest
@ -35,16 +76,21 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
std::string hairID = ref->base->hair; std::string hairID = ref->base->hair;
std::string headID = ref->base->head; 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 = //ESMStore::Races r =
const ESM::Race* race = mEnvironment.mWorld->getStore().races.find(ref->base->race); 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); 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); 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 ; /*std::cout << "Race: " << ref->base->race ;
if(female){ if(female){
@ -57,7 +103,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
std::string smodel = "meshes\\base_anim.nif"; std::string smodel = "meshes\\base_anim.nif";
if(beast) if(isBeast)
smodel = "meshes\\base_animkna.nif"; smodel = "meshes\\base_animkna.nif";
insert = ptr.getRefData().getBaseNode(); insert = ptr.getRefData().getBaseNode();
@ -66,6 +112,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
NifOgre::NIFLoader::load(smodel); NifOgre::NIFLoader::load(smodel);
base = mRend.getScene()->createEntity(smodel); base = mRend.getScene()->createEntity(smodel);
base->setVisibilityFlags(RV_Actors); base->setVisibilityFlags(RV_Actors);
bool transparent = false; bool transparent = false;
for (unsigned int i=0; i<base->getNumSubEntities(); ++i) 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->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones
//stay in the same place when we skipanim, or open a gui window //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); textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel);
insert->attachObject(base); insert->attachObject(base);
if(female)
if(isFemale)
insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); insert->scale(race->data.height.female, race->data.height.female, race->data.height.female);
else else
insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); insert->scale(race->data.height.male, race->data.height.male, race->data.height.male);
std::string headModel = "meshes\\" + std::cout << "Inv" << inv.getStateId() << "\n";
mEnvironment.mWorld->getStore().bodyParts.find(headID)->model; updateParts();
std::string hairModel = "meshes\\" + }
mEnvironment.mWorld->getStore().bodyParts.find(hairID)->model;
const ESM::BodyPart *chest = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest"); void NpcAnimation::updateParts(){
const ESM::BodyPart *upperleg = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg");
const ESM::BodyPart *groin = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin"); bool apparelChanged = false;
const ESM::BodyPart *arml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm"); //We need two
const ESM::BodyPart *neck = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck");
const ESM::BodyPart *knee = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee");
const ESM::BodyPart *ankle = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle");
const ESM::BodyPart *foot = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot");
const ESM::BodyPart *feet = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet");
const ESM::BodyPart *tail = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail");
const ESM::BodyPart *wristl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist"); //We need two
const ESM::BodyPart *forearml = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm"); //We need two
const ESM::BodyPart *handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand"); //We need two
const ESM::BodyPart *hair = mEnvironment.mWorld->getStore().bodyParts.search(hairID);
const ESM::BodyPart *head = mEnvironment.mWorld->getStore().bodyParts.search(headID);
if(bodyRaceID == "b_n_argonian_f_")
forearml = mEnvironment.mWorld->getStore().bodyParts.search ("b_n_argonian_m_forearm"); //We need two
if(!handl)
handl = mEnvironment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands");
//const ESM::BodyPart* claviclel = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "clavicle");
//const ESM::BodyPart* clavicler = claviclel;
const ESM::BodyPart* handr = handl;
const ESM::BodyPart* forearmr = forearml;
const ESM::BodyPart* wristr = wristl;
const ESM::BodyPart* armr = arml;
if(upperleg){ //inv.getSlot(MWWorld::InventoryStore::Slot_Robe);
insertBoundedPart("meshes\\" + upperleg->model + "*|", "Left Upper Leg"); if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){
insertBoundedPart("meshes\\" + upperleg->model, "Right Upper Leg"); //A robe was added or removed
removePartGroup(MWWorld::InventoryStore::Slot_Robe);
robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe);
apparelChanged = true;
}
if(skirtiter != inv.getSlot(MWWorld::InventoryStore::Slot_Skirt)){
//A robe was added or removed
removePartGroup(MWWorld::InventoryStore::Slot_Skirt);
skirtiter = inv.getSlot(MWWorld::InventoryStore::Slot_Skirt);
apparelChanged = true;
}
if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){
apparelChanged = true;
helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet);
removePartGroup(MWWorld::InventoryStore::Slot_Helmet);
} }
if(foot){ if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)){
if(bodyRaceID.compare("b_n_khajiit_m_") == 0) cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass);
removePartGroup(MWWorld::InventoryStore::Slot_Cuirass);
apparelChanged = true;
}
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())
{ {
feet = foot; 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 else
{ {
insertBoundedPart("meshes\\" + foot->model, "Right Foot"); const ESM::Armor *armor = (leftglove->get<ESM::Armor>())->base;
insertBoundedPart("meshes\\" + foot->model + "*|", "Left Foot"); std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts);
} }
} }
if(groin){ if(rightglove != inv.end()){
insertBoundedPart("meshes\\" + groin->model, "Groin");
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);
} }
if(knee) else
{ {
insertBoundedPart("meshes\\" + knee->model + "*|", "Left Knee"); //e const ESM::Armor *armor = (rightglove->get<ESM::Armor>())->base;
insertBoundedPart("meshes\\" + knee->model, "Right Knee"); //e std::vector<ESM::PartReference> parts = armor->parts.parts;
addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts);
}
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) if(shirt != inv.end()){
insertBoundedPart("meshes\\" + wristl->model + "*|", "Left Wrist"); 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;
/*if(claviclel) std::vector<ESM::PartReference> parts = clothes->parts.parts;
insertBoundedPart("meshes\\" + claviclel->model + "*|", "Left Clavicle", base); addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts);
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){ if(partpriorities[ESM::PRT_Head] < 1){
insertFreePart("meshes\\" + chest->model, ">\"", insert); 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);
}
}
if (handr){
insertFreePart("meshes\\" + handr->model , ">?", insert);
}
if (handl){
insertFreePart("meshes\\" + handl->model, ">>", insert);
}
if(tail){
insertFreePart("meshes\\" + tail->model, ">*", insert);
}
if(feet){
std::string num = getUniqueID(feet->model);
insertFreePart("meshes\\" + feet->model,"><", insert);
insertFreePart("meshes\\" + feet->model,">:", insert);
}
//originalpos = insert->_getWorldAABB().getCenter();
//originalscenenode = insert->getPosition();
} }
Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){
NIFLoader::load(mesh); NIFLoader::load(mesh);
Entity* ent = mRend.getScene()->createEntity(mesh); Ogre::Entity* part = mRend.getScene()->createEntity(mesh);
part->setVisibilityFlags(RV_Actors);
base->attachObjectToBone(bonename, ent); base->attachObjectToBone(bonename, part);
return ent; 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; std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix;
NIFLoader::load(meshNumbered); NIFLoader::load(meshNumbered);
Ogre::Entity* ent = mRend.getScene()->createEntity(meshNumbered); Ogre::Entity* part = mRend.getScene()->createEntity(meshNumbered);
part->setVisibilityFlags(RV_Actors);
insert->attachObject(part);
std::vector<Nif::NiTriShapeCopy>* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix));
if(shape){
insert->attachObject(ent); handleShapes(shape, part, base->getSkeleton());
entityparts.push_back(ent);
shapes = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix));
if(shapes){
shapeparts.push_back(shapes);
handleShapes(shapes, ent, base->getSkeleton());
} }
std::pair<Ogre::Entity*, std::vector<Nif::NiTriShapeCopy>*> pair = std::make_pair(part, shape);
return pair;
} }
void NpcAnimation::runAnimation(float timepassed){ void NpcAnimation::runAnimation(float timepassed){
if(timeToChange > .2){
timeToChange = 0;
updateParts();
}
timeToChange += timepassed;
//1. Add the amount of time passed to time //1. Add the amount of time passed to time
//2. Handle the animation transforms dependent on time //2. Handle the animation transforms dependent on time
@ -286,21 +554,287 @@ void NpcAnimation::runAnimation(float timepassed){
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(); vecRotPos.clear();
std::vector<Nif::NiTriShapeCopy>* shapes = *shapepartsiter;
Ogre::Entity* theentity = *entitypartsiter;
handleShapes(shapes, theentity, base->getSkeleton()); if(lBeastFoot.first)
shapepartsiter++; handleShapes(lBeastFoot.second, lBeastFoot.first, base->getSkeleton());
entitypartsiter++; 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/property.hpp>
#include <components/nif/controller.hpp> #include <components/nif/controller.hpp>
#include <components/nif/extra.hpp> #include <components/nif/extra.hpp>
#include <utility>
#include "../mwworld/refdata.hpp" #include "../mwworld/refdata.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/environment.hpp" #include "../mwworld/environment.hpp"
#include "components/nifogre/ogre_nif_loader.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{ namespace MWRender{
class NpcAnimation: public Animation{ 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: 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(); virtual ~NpcAnimation();
Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); 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); 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->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
sg->setCastShadows(true);
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
mRenderer.getScene()->destroyEntity(ent); mRenderer.getScene()->destroyEntity(ent);

View file

@ -60,6 +60,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode(); mBBNodeReal = mRendering->getScene()->getRootSceneNode()->createChildSceneNode();
mBBQueryTotal = mRendering->getScene()->createBillboardSet(1); mBBQueryTotal = mRendering->getScene()->createBillboardSet(1);
mBBQueryTotal->setCastShadows(false);
mBBQueryTotal->setDefaultDimensions(150, 150); mBBQueryTotal->setDefaultDimensions(150, 150);
mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->createBillboard(Vector3::ZERO);
mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setMaterialName("QueryTotalPixels");
@ -67,6 +68,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBNodeReal->attachObject(mBBQueryTotal); mBBNodeReal->attachObject(mBBQueryTotal);
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
mBBQueryVisible->setCastShadows(false);
mBBQueryVisible->setDefaultDimensions(150, 150); mBBQueryVisible->setDefaultDimensions(150, 150);
mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->createBillboard(Vector3::ZERO);
mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setMaterialName("QueryVisiblePixels");
@ -75,6 +77,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
/// \todo ideally this should occupy exactly 1 pixel on the screen /// \todo ideally this should occupy exactly 1 pixel on the screen
mBBQuerySingleObject->setCastShadows(false);
mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003); mBBQuerySingleObject->setDefaultDimensions(0.003, 0.003);
mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->createBillboard(Vector3::ZERO);
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");

View file

@ -14,6 +14,10 @@
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "shadows.hpp"
#include "shaderhelper.hpp"
#include "localmap.hpp"
#include "water.hpp"
using namespace MWRender; using namespace MWRender;
using namespace Ogre; using namespace Ogre;
@ -21,11 +25,9 @@ using namespace Ogre;
namespace MWRender { namespace MWRender {
RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine, MWWorld::Environment& environment) 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); mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5);
mTerrainManager = new TerrainManager(mRendering.getScene(),
environment);
mWater = 0; mWater = 0;
@ -54,6 +56,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
if (caps->getNumMultiRenderTargets() < 2) if (caps->getNumMultiRenderTargets() < 2)
Settings::Manager::setBool("shader", "Water", false); 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 // note that the order is important here
if (useMRT()) if (useMRT())
@ -86,6 +90,12 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode(); Ogre::SceneNode *cameraPitchNode = cameraYawNode->createChildSceneNode();
cameraPitchNode->attachObject(mRendering.getCamera()); cameraPitchNode->attachObject(mRendering.getCamera());
mShadows = new Shadows(&mRendering);
mShaderHelper = new ShaderHelper(this);
mTerrainManager = new TerrainManager(mRendering.getScene(), this,
environment);
//mSkyManager = 0; //mSkyManager = 0;
mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment); mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera(), &environment);
@ -100,7 +110,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
RenderingManager::~RenderingManager () RenderingManager::~RenderingManager ()
{ {
//TODO: destroy mSun?
delete mPlayer; delete mPlayer;
delete mSkyManager; delete mSkyManager;
delete mDebugging; delete mDebugging;
@ -412,6 +421,7 @@ void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr)
void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{ {
if (!mSunEnabled) return;
mSun->setDiffuseColour(colour); mSun->setDiffuseColour(colour);
mSun->setSpecularColour(colour); mSun->setSpecularColour(colour);
mTerrainManager->setDiffuse(colour); mTerrainManager->setDiffuse(colour);
@ -425,12 +435,21 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
void RenderingManager::sunEnable() 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() 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) void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
@ -463,11 +482,13 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell)
void RenderingManager::disableLights() void RenderingManager::disableLights()
{ {
mObjects.disableLights(); mObjects.disableLights();
sunDisable();
} }
void RenderingManager::enableLights() void RenderingManager::enableLights()
{ {
mObjects.enableLights(); mObjects.enableLights();
sunEnable();
} }
const bool RenderingManager::useMRT() const bool RenderingManager::useMRT()
@ -475,4 +496,9 @@ const bool RenderingManager::useMRT()
return Settings::Manager::getBool("shader", "Water"); return Settings::Manager::getBool("shader", "Water");
} }
Shadows* RenderingManager::getShadows()
{
return mShadows;
}
} // namespace } // namespace

View file

@ -25,8 +25,6 @@
#include "objects.hpp" #include "objects.hpp"
#include "actors.hpp" #include "actors.hpp"
#include "player.hpp" #include "player.hpp"
#include "water.hpp"
#include "localmap.hpp"
#include "occlusionquery.hpp" #include "occlusionquery.hpp"
namespace Ogre namespace Ogre
@ -45,7 +43,10 @@ namespace MWWorld
namespace MWRender namespace MWRender
{ {
class Shadows;
class ShaderHelper;
class LocalMap;
class Water;
class RenderingManager: private RenderingInterface { class RenderingManager: private RenderingInterface {
@ -114,6 +115,8 @@ class RenderingManager: private RenderingInterface {
bool occlusionQuerySupported() { return mOcclusionQuery->supported(); }; bool occlusionQuerySupported() { return mOcclusionQuery->supported(); };
OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; }; OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; };
Shadows* getShadows();
void setGlare(bool glare); void setGlare(bool glare);
void skyEnable (); void skyEnable ();
void skyDisable (); void skyDisable ();
@ -149,6 +152,8 @@ class RenderingManager: private RenderingInterface {
void setAmbientMode(); void setAmbientMode();
bool mSunEnabled;
SkyManager* mSkyManager; SkyManager* mSkyManager;
OcclusionQuery* mOcclusionQuery; OcclusionQuery* mOcclusionQuery;
@ -180,6 +185,10 @@ class RenderingManager: private RenderingInterface {
MWRender::Debugging *mDebugging; MWRender::Debugging *mDebugging;
MWRender::LocalMap* mLocalMap; 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->setPosition(finalPosition);
mNode->attachObject(mBBSet); mNode->attachObject(mBBSet);
mBBSet->createBillboard(0,0,0); mBBSet->createBillboard(0,0,0);
mBBSet->setCastShadows(false);
mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
mMaterial->removeAllTechniques(); mMaterial->removeAllTechniques();
@ -450,6 +451,7 @@ void SkyManager::create()
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false);
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
mAtmosphereNight->attachObject(night1_ent); mAtmosphereNight->attachObject(night1_ent);
@ -525,6 +527,7 @@ void SkyManager::create()
// Atmosphere (day) // Atmosphere (day)
mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif");
Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif"); Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif");
atmosphere_ent->setCastShadows(false);
ModVertexAlpha(atmosphere_ent, 0); ModVertexAlpha(atmosphere_ent, 0);
@ -596,6 +599,7 @@ void SkyManager::create()
SceneNode* clouds_node = mRootNode->createChildSceneNode(); SceneNode* clouds_node = mRootNode->createChildSceneNode();
clouds_node->attachObject(clouds_ent); clouds_node->attachObject(clouds_ent);
mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial();
clouds_ent->setCastShadows(false);
// Clouds vertex shader // Clouds vertex shader
HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, 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); mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
mCloudMaterial->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(""); mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("");
mCreated = true; mCreated = true;
@ -766,12 +772,14 @@ void SkyManager::disable()
void SkyManager::setMoonColour (bool red) void SkyManager::setMoonColour (bool red)
{ {
if (!mCreated) return;
mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784) mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784)
: ColourValue(1.0, 1.0, 1.0)); : ColourValue(1.0, 1.0, 1.0));
} }
void SkyManager::setCloudsOpacity(float opacity) void SkyManager::setCloudsOpacity(float opacity)
{ {
if (!mCreated) return;
mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity)); 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) void SkyManager::setMasserFade(const float fade)
{ {
if (!mCreated) return;
mMasser->setVisibility(fade); mMasser->setVisibility(fade);
} }
void SkyManager::setSecundaFade(const float fade) void SkyManager::setSecundaFade(const float fade)
{ {
if (!mCreated) return;
mSecunda->setVisibility(fade); mSecunda->setVisibility(fade);
} }

View file

@ -7,7 +7,8 @@
#include "terrainmaterial.hpp" #include "terrainmaterial.hpp"
#include "terrain.hpp" #include "terrain.hpp"
#include "renderconst.hpp" #include "renderconst.hpp"
#include "shadows.hpp"
#include <components/settings/settings.hpp>
using namespace Ogre; using namespace Ogre;
@ -16,8 +17,8 @@ namespace MWRender
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
TerrainManager::TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& evn) : TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& evn) :
mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)) mEnvironment(evn), mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend)
{ {
TerrainMaterialGeneratorPtr matGen; TerrainMaterialGeneratorPtr matGen;
@ -48,9 +49,19 @@ namespace MWRender
mActiveProfile->setLayerSpecularMappingEnabled(false); mActiveProfile->setLayerSpecularMappingEnabled(false);
mActiveProfile->setLayerNormalMappingEnabled(false); mActiveProfile->setLayerNormalMappingEnabled(false);
mActiveProfile->setLayerParallaxMappingEnabled(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 //disabled
mActiveProfile->setCompositeMapEnabled(false); mActiveProfile->setCompositeMapEnabled(false);

View file

@ -24,7 +24,7 @@ namespace MWRender{
*/ */
class TerrainManager{ class TerrainManager{
public: public:
TerrainManager(Ogre::SceneManager* mgr, const MWWorld::Environment& env); TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend, const MWWorld::Environment& env);
virtual ~TerrainManager(); virtual ~TerrainManager();
void setDiffuse(const Ogre::ColourValue& diffuse); void setDiffuse(const Ogre::ColourValue& diffuse);
@ -37,6 +37,7 @@ namespace MWRender{
Ogre::TerrainGroup mTerrainGroup; Ogre::TerrainGroup mTerrainGroup;
const MWWorld::Environment& mEnvironment; const MWWorld::Environment& mEnvironment;
RenderingManager* mRendering;
Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile;

View file

@ -39,6 +39,8 @@ THE SOFTWARE.
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "renderingmanager.hpp" #include "renderingmanager.hpp"
#undef far
namespace Ogre namespace Ogre
{ {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
@ -86,6 +88,7 @@ namespace Ogre
, mPSSM(0) , mPSSM(0)
, mDepthShadows(false) , mDepthShadows(false)
, mLowLodShadows(false) , mLowLodShadows(false)
, mShadowFar(1300)
{ {
} }
@ -101,6 +104,24 @@ namespace Ogre
terrain->_setNormalMapRequired(true); terrain->_setNormalMapRequired(true);
terrain->_setLightMapRequired(mLightmapEnabled, true); terrain->_setLightMapRequired(mLightmapEnabled, true);
terrain->_setCompositeMapRequired(mCompositeMapEnabled); 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) void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled)
@ -462,6 +483,7 @@ namespace Ogre
StringUtil::StrStreamType sourceStr; StringUtil::StrStreamType sourceStr;
generateFragmentProgramSource(prof, terrain, tt, sourceStr); generateFragmentProgramSource(prof, terrain, tt, sourceStr);
ret->setSource(sourceStr.str()); ret->setSource(sourceStr.str());
ret->load(); ret->load();
defaultFpParams(prof, terrain, tt, ret); defaultFpParams(prof, terrain, tt, ret);
@ -518,7 +540,6 @@ namespace Ogre
params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX); params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX);
params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM, params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM,
Terrain::LOD_MORPH_CUSTOM_PARAM); Terrain::LOD_MORPH_CUSTOM_PARAM);
params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
{ {
@ -533,8 +554,8 @@ namespace Ogre
GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i);
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
params->setNamedAutoConstant("depthRange" + StringConverter::toString(i), //params->setNamedAutoConstant("depthRange" + StringConverter::toString(i),
GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, 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("lightPosObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i);
params->setNamedAutoConstant("lightDiffuseColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 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("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i);
//params->setNamedAutoConstant("lightSpecularColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 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("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
{ {
params->setNamedConstant("shadowFar_fadeStart", Vector4(prof->mShadowFar, prof->mShadowFadeStart * prof->mShadowFar, 0, 0));
uint numTextures = 1; uint numTextures = 1;
if (prof->getReceiveDynamicShadowsPSSM()) if (prof->getReceiveDynamicShadowsPSSM())
{ {
@ -732,7 +755,7 @@ namespace Ogre
ret->unload(); 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"); ret->setParameter("entry_point", "main_vp");
return ret; return ret;
@ -794,7 +817,7 @@ namespace Ogre
uint texCoordSet = 1; uint texCoordSet = 1;
outStream << 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 // layer UV's premultiplied, packed as xy/zw
uint numUVSets = numLayers / 2; uint numUVSets = numLayers / 2;
@ -814,14 +837,6 @@ namespace Ogre
outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n"; 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)) if (prof->isShadowingEnabled(tt, terrain))
{ {
texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream); texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream);
@ -831,7 +846,7 @@ namespace Ogre
if (texCoordSet > 8) if (texCoordSet > 8)
{ {
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 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__); __FUNCTION__);
} }
@ -921,7 +936,7 @@ namespace Ogre
uint texCoordSet = 1; uint texCoordSet = 1;
outStream << outStream <<
"float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n"; "float4 uvMisc : COLOR0,\n";
// UV's premultiplied, packed as xy/zw // UV's premultiplied, packed as xy/zw
uint maxLayers = prof->getMaxLayers(terrain); uint maxLayers = prof->getMaxLayers(terrain);
@ -948,8 +963,8 @@ namespace Ogre
if (fog) if (fog)
{ {
outStream << outStream <<
"uniform float3 fogColour, \n" "uniform float4 fogParams, \n"
"float fogVal : COLOR,\n"; "uniform float3 fogColour, \n";
} }
uint currentSamplerIdx = 0; uint currentSamplerIdx = 0;
@ -968,7 +983,7 @@ namespace Ogre
//"uniform float3 lightSpecularColour"<<i<<",\n" //"uniform float3 lightSpecularColour"<<i<<",\n"
; ;
if (prof->getNumberOfLightsSupported() > 1) if (i > 0)
outStream << outStream <<
"uniform float4 lightAttenuation"<<i<<",\n"; "uniform float4 lightAttenuation"<<i<<",\n";
@ -1137,7 +1152,7 @@ namespace Ogre
outStream << " float3 halfAngle"<<i<<" = normalize(lightDir"<<i<<" + eyeDir);\n" 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"; " float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normal), dot(halfAngle"<<i<<", normal), scaleBiasSpecular.z);\n";
if (prof->getNumberOfLightsSupported() > 1) if (i > 0)
outStream << outStream <<
// pre-multiply light color with attenuation factor // pre-multiply light color with attenuation factor
"d = length( lightDir"<<i<<" ); \n" "d = length( lightDir"<<i<<" ); \n"
@ -1249,22 +1264,7 @@ namespace Ogre
outStream << outStream <<
" // pass cam depth\n" " // pass cam depth\n"
" oUVMisc.z = oPos.z;\n"; " oPosObj.w = 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";
}
}
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
generateVpDynamicShadows(prof, terrain, tt, outStream); generateVpDynamicShadows(prof, terrain, tt, outStream);
@ -1315,7 +1315,13 @@ namespace Ogre
// diffuse lighting // diffuse lighting
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i) 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"; outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse * shadow;\n";
else
outStream << " outputCol.rgb += litRes"<<i<<".y * lightDiffuseColour"<<i<<" * diffuse;\n";
}
// specular default // specular default
if (!prof->isLayerSpecularMappingEnabled()) if (!prof->isLayerSpecularMappingEnabled())
@ -1343,6 +1349,16 @@ namespace Ogre
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog) 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"; outStream << " outputCol.rgb = lerp(outputCol.rgb, fogColour, fogVal);\n";
} }
@ -1350,7 +1366,7 @@ namespace Ogre
outStream << " oColor = outputCol;\n"; outStream << " oColor = outputCol;\n";
if (MWRender::RenderingManager::useMRT()) outStream << if (MWRender::RenderingManager::useMRT()) outStream <<
" oColor1 = float4(uvMisc.z / far, 0, 0, 1); \n"; " oColor1 = float4(position.w / far, 0, 0, 1); \n";
outStream outStream
<< "}\n"; << "}\n";
@ -1364,7 +1380,7 @@ namespace Ogre
outStream << outStream <<
"// Simple PCF \n" "// Simple PCF \n"
"// Number of samples in one dimension (square for total samples) \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_FILTER_SCALE 1 \n"
"#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n" "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n"
@ -1377,28 +1393,18 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
"float calcDepthShadow(sampler2D shadowMap, float4 uv, float invShadowMapSize) \n" "float calcDepthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \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" " { \n"
" float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n" " shadowMapPos = shadowMapPos / shadowMapPos.w; \n"
" // manually project and assign derivatives \n" " float2 uv = shadowMapPos.xy; \n"
" // to avoid gradient issues inside loops \n" " float3 o = float3(offset, -offset.x) * 0.3f; \n"
" newUV = newUV / newUV.w; \n" " // Note: We using 2x2 PCF. Good enough and is alot faster. \n"
" float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n" " float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n"
" if (depth >= 1 || depth >= uv.z)\n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n"
" shadow += 1.0;\n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n"
" } \n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n"
" return c / 4; \n"
" shadow /= SHADOW_SAMPLES; \n" " } \n";
" return shadow; \n"
"} \n";
} }
else else
{ {
@ -1436,7 +1442,7 @@ namespace Ogre
{ {
outStream << "\n "; outStream << "\n ";
for (uint i = 0; i < numTextures; ++i) for (uint i = 0; i < numTextures; ++i)
outStream << "float invShadowmapSize" << i << ", "; outStream << "float2 invShadowmapSize" << i << ", ";
} }
outStream << "\n" outStream << "\n"
" float4 pssmSplitPoints, float camDepth) \n" " float4 pssmSplitPoints, float camDepth) \n"
@ -1458,7 +1464,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
" shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << "); \n"; " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << ".xy); \n";
} }
else else
{ {
@ -1520,8 +1526,8 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
// make linear // make linear
outStream << //outStream <<
"oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; // "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n";
} }
} }
@ -1538,6 +1544,8 @@ namespace Ogre
// in semantics & params // in semantics & params
uint numTextures = 1; uint numTextures = 1;
outStream <<
", uniform float4 shadowFar_fadeStart \n";
if (prof->getReceiveDynamicShadowsPSSM()) if (prof->getReceiveDynamicShadowsPSSM())
{ {
numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
@ -1554,7 +1562,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
", uniform float inverseShadowmapSize" << i << " \n"; ", uniform float4 inverseShadowmapSize" << i << " \n";
} }
} }
@ -1567,7 +1575,7 @@ namespace Ogre
{ {
uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount();
outStream << outStream <<
" float camDepth = uvMisc.z;\n"; " float camDepth = position.w;\n";
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
@ -1589,7 +1597,7 @@ namespace Ogre
{ {
outStream << "\n "; outStream << "\n ";
for (uint i = 0; i < numTextures; ++i) for (uint i = 0; i < numTextures; ++i)
outStream << "inverseShadowmapSize" << i << ", "; outStream << "inverseShadowmapSize" << i << ".xy, ";
} }
outStream << "\n" << outStream << "\n" <<
" pssmSplitPoints, camDepth);\n"; " pssmSplitPoints, camDepth);\n";
@ -1600,7 +1608,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
" float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0);"; " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0.xy);";
} }
else else
{ {
@ -1610,6 +1618,10 @@ 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"; " shadow = min(shadow, rtshadow);\n";
} }

View file

@ -73,6 +73,9 @@ namespace Ogre
void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain); void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain);
void requestOptions(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). /** Whether to support normal mapping per layer in the shader (default true).
*/ */
bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; } bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; }
@ -245,6 +248,8 @@ namespace Ogre
bool mDepthShadows; bool mDepthShadows;
bool mLowLodShadows; bool mLowLodShadows;
bool mSM3Available; bool mSM3Available;
float mShadowFar;
float mShadowFadeStart;
bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const; 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) : Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()),
mIsUnderwater(false), mVisibilityFlags(0), mIsUnderwater(false), mVisibilityFlags(0),
mReflectionTarget(0), mActive(1) mReflectionTarget(0), mActive(1), mToggled(1)
{ {
mSky = sky; mSky = sky;
@ -31,6 +31,7 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mWater = mSceneManager->createEntity("water"); mWater = mSceneManager->createEntity("water");
mWater->setVisibilityFlags(RV_Water); mWater->setVisibilityFlags(RV_Water);
mWater->setRenderQueueGroup(RQG_Water); mWater->setRenderQueueGroup(RQG_Water);
mWater->setCastShadows(false);
mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water")
+ RV_Statics * Settings::Manager::getBool("reflect statics", "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 = mSceneManager->getRootSceneNode()->createChildSceneNode();
mWaterNode->setPosition(0, mTop, 0); mWaterNode->setPosition(0, mTop, 0);
mReflectionCamera = mSceneManager->createCamera("ReflectionCamera");
if(!(cell->data.flags & cell->Interior)) if(!(cell->data.flags & cell->Interior))
{ {
mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); 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 // Create rendertarget for reflection
int rttsize = Settings::Manager::getInt("rtt size", "Water"); int rttsize = Settings::Manager::getInt("rtt size", "Water");
TexturePtr tex;
if (Settings::Manager::getBool("shader", "Water")) if (Settings::Manager::getBool("shader", "Water"))
{ {
TexturePtr tex = TextureManager::getSingleton().createManual("WaterReflection", tex = TextureManager::getSingleton().createManual("WaterReflection",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_R8G8B8, TU_RENDERTARGET); ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET);
RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
Viewport* vp = rtt->addViewport(mCamera); Viewport* vp = rtt->addViewport(mReflectionCamera);
vp->setOverlaysEnabled(false); vp->setOverlaysEnabled(false);
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setVisibilityMask( mVisibilityFlags ); 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->addListener(this);
rtt->setActive(true); rtt->setActive(true);
@ -74,13 +80,61 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mWater->setMaterial(mMaterial); mWater->setMaterial(mMaterial);
mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); 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) void Water::setActive(bool active)
{ {
mActive = active; mActive = active;
if (mReflectionTarget) mReflectionTarget->setActive(active && !mIsUnderwater); updateVisible();
mWater->setVisible(active);
} }
Water::~Water() Water::~Water()
@ -112,8 +166,8 @@ void Water::setHeight(const float height)
void Water::toggle() void Water::toggle()
{ {
if (mActive) mToggled = !mToggled;
mWater->setVisible(!mWater->getVisible()); updateVisible();
} }
void Water::checkUnderwater(float y) void Water::checkUnderwater(float y)
@ -128,9 +182,6 @@ void Water::checkUnderwater(float y)
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0)); pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0));
if (mReflectionTarget)
mReflectionTarget->setActive(mActive);
mWater->setRenderQueueGroup(RQG_Water); mWater->setRenderQueueGroup(RQG_Water);
mIsUnderwater = false; mIsUnderwater = false;
@ -146,13 +197,12 @@ void Water::checkUnderwater(float y)
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1)); pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1));
if (mReflectionTarget)
mReflectionTarget->setActive(false);
mWater->setRenderQueueGroup(RQG_UnderWater); mWater->setRenderQueueGroup(RQG_UnderWater);
mIsUnderwater = true; mIsUnderwater = true;
} }
updateVisible();
} }
Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
@ -164,7 +214,12 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
{ {
if (evt.source == mReflectionTarget) 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 // Some messy code to get the skybox to show up at all
// The problem here is that it gets clipped by the water plane // 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->setSkyPosition(pos);
mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f);
mCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop));
mCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop));
} }
} }
void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
{ {
mWater->setVisible(true);
if (evt.source == mReflectionTarget) if (evt.source == mReflectionTarget)
{ {
mSky->resetSkyPosition(); mSky->resetSkyPosition();
mSky->scaleSky(1); mSky->scaleSky(1);
mCamera->disableReflection(); mReflectionCamera->disableCustomNearClipPlane();
mCamera->disableCustomNearClipPlane(); mReflectionCamera->disableReflection();
} }
} }
@ -230,4 +283,11 @@ void Water::setViewportBackground(const ColourValue& bg)
mReflectionTarget->getViewport(0)->setBackgroundColour(bg); mReflectionTarget->getViewport(0)->setBackgroundColour(bg);
} }
void Water::updateVisible()
{
mWater->setVisible(mToggled && mActive);
if (mReflectionTarget)
mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater);
}
} // namespace } // namespace

View file

@ -24,6 +24,7 @@ namespace MWRender {
bool mIsUnderwater; bool mIsUnderwater;
bool mActive; bool mActive;
bool mToggled;
int mTop; int mTop;
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
@ -31,6 +32,7 @@ namespace MWRender {
protected: protected:
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void updateVisible();
SkyManager* mSky; SkyManager* mSky;
@ -39,6 +41,8 @@ namespace MWRender {
void createMaterial(); void createMaterial();
Ogre::MaterialPtr mMaterial; Ogre::MaterialPtr mMaterial;
Ogre::Camera* mReflectionCamera;
Ogre::RenderTarget* mReflectionTarget; Ogre::RenderTarget* mReflectionTarget;
bool mUnderwaterEffect; bool mUnderwaterEffect;

View file

@ -11,6 +11,7 @@
#include "../mwdialogue/dialoguemanager.hpp" #include "../mwdialogue/dialoguemanager.hpp"
#include "interpretercontext.hpp" #include "interpretercontext.hpp"
#include "ref.hpp"
namespace MWScript 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 opcodeJournal = 0x2000133;
const int opcodeSetJournalIndex = 0x2000134; const int opcodeSetJournalIndex = 0x2000134;
const int opcodeGetJournalIndex = 0x2000135; const int opcodeGetJournalIndex = 0x2000135;
const int opcodeAddTopic = 0x200013a; const int opcodeAddTopic = 0x200013a;
const int opcodeChoice = 0x2000a; const int opcodeChoice = 0x2000a;
const int opcodeForceGreeting = 0x200014f;
const int opcodeForceGreetingExplicit = 0x2000150;
void registerExtensions (Compiler::Extensions& extensions) void registerExtensions (Compiler::Extensions& extensions)
{ {
@ -129,6 +145,9 @@ namespace MWScript
extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex); extensions.registerFunction ("getjournalindex", 'l', "c", opcodeGetJournalIndex);
extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic); extensions.registerInstruction ("addtopic", "S" , opcodeAddTopic);
extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice); extensions.registerInstruction ("choice", "/SlSlSlSlSlSlSlSlSlSlSlSlSlSlSlSl", opcodeChoice);
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting);
extensions.registerInstruction("forcegreeting","",opcodeForceGreeting,
opcodeForceGreetingExplicit);
} }
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
@ -138,6 +157,8 @@ namespace MWScript
interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex); interpreter.installSegment5 (opcodeGetJournalIndex, new OpGetJournalIndex);
interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic); interpreter.installSegment5 (opcodeAddTopic, new OpAddTopic);
interpreter.installSegment3 (opcodeChoice,new OpChoice); 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 0x20008: LoopAnim
op 0x20009: LoopAnim, explicit reference op 0x20009: LoopAnim, explicit reference
op 0x2000a: Choice 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: Segment 4:
(not implemented yet) (not implemented yet)
@ -129,4 +134,14 @@ op 0x2000143: ModWaterLevel
op 0x2000144: ToggleWater, twa op 0x2000144: ToggleWater, twa
op 0x2000145: ToggleFogOfWar (tfow) op 0x2000145: ToggleFogOfWar (tfow)
op 0x2000146: TogglePathgrid 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 <components/interpreter/opcodes.hpp>
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -15,6 +17,8 @@
#include "interpretercontext.hpp" #include "interpretercontext.hpp"
#include "ref.hpp" #include "ref.hpp"
#include "../mwdialogue/dialoguemanager.hpp"
namespace MWScript namespace MWScript
{ {
namespace Stats 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 numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027; const int opcodeGetAttribute = 0x2000027;
@ -311,6 +529,21 @@ namespace MWScript
const int opcodeModSkill = 0x20000fa; const int opcodeModSkill = 0x20000fa;
const int opcodeModSkillExplicit = 0x2000115; 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) void registerExtensions (Compiler::Extensions& extensions)
{ {
static const char *attributes[numberOfAttributes] = static const char *attributes[numberOfAttributes] =
@ -381,6 +614,18 @@ namespace MWScript
extensions.registerInstruction (mod + skills[i], "l", extensions.registerInstruction (mod + skills[i], "l",
opcodeModSkill+i, opcodeModSkillExplicit+i); 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) void installOpcodes (Interpreter::Interpreter& interpreter)
@ -436,6 +681,22 @@ namespace MWScript
interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill<ImplicitRef> (i)); interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill<ImplicitRef> (i));
interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill<ExplicitRef> (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

@ -13,6 +13,7 @@
#include "OgreTextureManager.h" #include "OgreTextureManager.h"
using namespace Ogre; using namespace Ogre;
namespace MWWorld namespace MWWorld
{ {
@ -20,9 +21,11 @@ namespace MWWorld
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0), mFreeFly (true) mRender(_rend), mEngine(0), mFreeFly (true)
{ {
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
} }
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
@ -91,6 +94,7 @@ namespace MWWorld
//set the DebugRenderingMode. To disable it,set it to 0 //set the DebugRenderingMode. To disable it,set it to 0
//eng->setDebugRenderingMode(1); //eng->setDebugRenderingMode(1);
//set the walkdirection to 0 (no movement) for every actor) //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++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
@ -98,31 +102,52 @@ namespace MWWorld
act->setWalkDirection(btVector3(0,0,0)); 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()); for (std::vector<std::pair<std::string, Ogre::Vector3> >::const_iterator iter (actors.begin());
iter!=actors.end(); ++iter) iter!=actors.end(); ++iter)
{ {
OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first); 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! //dirty stuff to get the camera orientation. Must be changed!
Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first); Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first);
Ogre::Vector3 dir; Ogre::Vector3 dir;
Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); Ogre::Node* yawNode = sceneNode->getChildIterator().getNext();
Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); Ogre::Node* pitchNode = yawNode->getChildIterator().getNext();
if(mFreeFly)
{
Ogre::Quaternion yawQuat = yawNode->getOrientation(); Ogre::Quaternion yawQuat = yawNode->getOrientation();
Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); Ogre::Quaternion pitchQuat = pitchNode->getOrientation();
Ogre::Quaternion both = yawQuat * pitchQuat;
//playerphysics->ps.viewangles.z = both.getPitch().valueDegrees();
if(mFreeFly)
{
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); 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); dir = 0.07*(yawQuat*pitchQuat*dir1);
} }
else else
{ {
Ogre::Quaternion quat = yawNode->getOrientation(); Ogre::Quaternion quat = yawNode->getOrientation();
Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y);
dir = 0.025*(quat*dir1); dir = 0.025*(quat*dir1);
} }
//set the walk direction //set the walk direction
act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y));
} }
@ -132,13 +157,14 @@ namespace MWWorld
for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) for(std::map<std::string,OEngine::Physic::PhysicActor*>::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++)
{ {
btVector3 newPos = it->second->getPosition(); btVector3 newPos = it->second->getPosition();
Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z());
response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord)); response.push_back(std::pair<std::string, Ogre::Vector3>(it->first, coord));
} }
return response; return response;
} }
void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh,
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position)
{ {

View file

@ -54,6 +54,7 @@ namespace MWWorld
OEngine::Physic::PhysicEngine* mEngine; OEngine::Physic::PhysicEngine* mEngine;
bool mFreeFly; bool mFreeFly;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (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

@ -83,6 +83,8 @@ ELSE (WIN32) #Unix
CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR) CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR)
FIND_PACKAGE(PkgConfig) FIND_PACKAGE(PkgConfig)
IF(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) PKG_SEARCH_MODULE(MYGUI MYGUIStatic MyGUIStatic)
IF (MYGUI_INCLUDE_DIRS) IF (MYGUI_INCLUDE_DIRS)
SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS}) SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS})
@ -97,6 +99,16 @@ ELSE (WIN32) #Unix
STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}") STRING(REGEX REPLACE "(.*)/.*" "\\1" MYGUI_LIB_DIR "${MYGUI_LIB_DIR}")
STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}") STRING(REGEX REPLACE ".*/" "" MYGUI_LIBRARIES "${MYGUI_LIBRARIES}")
ENDIF (MYGUI_INCLUDE_DIRS) 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) ELSE(MYGUI_STATIC)
PKG_SEARCH_MODULE(MYGUI MYGUI MyGUI) PKG_SEARCH_MODULE(MYGUI MYGUI MyGUI)
IF (MYGUI_INCLUDE_DIRS) IF (MYGUI_INCLUDE_DIRS)
@ -120,17 +132,23 @@ SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS)
SEPARATE_ARGUMENTS(MYGUI_LIBRARIES) SEPARATE_ARGUMENTS(MYGUI_LIBRARIES)
SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES) SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES)
SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} ${FREETYPE_LIBRARIES})
SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS} CACHE PATH "") SET(MYGUI_INCLUDE_DIRS ${MYGUI_INCLUDE_DIRS} CACHE PATH "")
SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "") SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} CACHE STRING "")
SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "") SET(MYGUI_PLATFORM_LIBRARIES ${MYGUI_PLATFORM_LIBRARIES} CACHE STRING "")
SET(MYGUI_LIB_DIR ${MYGUI_LIB_DIR} CACHE PATH "") 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) SET(MYGUI_FOUND TRUE)
ENDIF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES) ENDIF (MYGUI_INCLUDE_DIRS AND MYGUI_LIBRARIES AND FREETYPE_LIBRARIES)
IF (MYGUI_FOUND) IF (MYGUI_FOUND)
MARK_AS_ADVANCED(MYGUI_LIB_DIR) MARK_AS_ADVANCED(MYGUI_LIB_DIR)
IF (NOT MYGUI_FIND_QUIETLY) IF (NOT MYGUI_FIND_QUIETLY)
MESSAGE(STATUS " libraries : ${MYGUI_LIBRARIES} from ${MYGUI_LIB_DIR}") MESSAGE(STATUS " libraries : ${MYGUI_LIBRARIES} from ${MYGUI_LIB_DIR}")
MESSAGE(STATUS " includes : ${MYGUI_INCLUDE_DIRS}") MESSAGE(STATUS " includes : ${MYGUI_INCLUDE_DIRS}")

View file

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

View file

@ -79,7 +79,7 @@ class DirArchive: public Ogre::FileSystemArchive
{ {
passed = filename.substr(0, filename.length() - 2); 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); passed = filename.substr(0, filename.length() - 6);
copy = passed; copy = passed;
} }
@ -232,7 +232,7 @@ public:
{ {
passed = filename.substr(0, filename.length() - 2); 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); passed = filename.substr(0, filename.length() - 6);
// Open the file // Open the file
StreamPtr strm = narc->getFile(passed.c_str()); StreamPtr strm = narc->getFile(passed.c_str());
@ -254,7 +254,7 @@ bool exists(const String& filename) {
{ {
passed = filename.substr(0, filename.length() - 2); 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); passed = filename.substr(0, filename.length() - 6);
return arc.exists(passed.c_str()); return arc.exists(passed.c_str());

View file

@ -11,6 +11,7 @@ void PartReferenceList::load(ESMReader &esm)
esm.getHT(pr.part); // The INDX byte esm.getHT(pr.part); // The INDX byte
pr.male = esm.getHNOString("BNAM"); pr.male = esm.getHNOString("BNAM");
pr.female = esm.getHNOString("CNAM"); pr.female = esm.getHNOString("CNAM");
parts.push_back(pr);
} }
} }

View file

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

View file

@ -26,6 +26,7 @@
#include "ogre_nif_loader.hpp" #include "ogre_nif_loader.hpp"
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/nifoverrides/nifoverrides.hpp>
typedef unsigned char ubyte; typedef unsigned char ubyte;
@ -281,16 +282,62 @@ void NIFLoader::createMaterial(const String &name,
// NiAlphaProperty in nif/property.h if you need to decode // NiAlphaProperty in nif/property.h if you need to decode
// other values. 237 basically means normal transparencly. // other values. 237 basically means normal transparencly.
if (alphaFlags == 237) if (alphaFlags == 237)
{
NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName);
if (result.first)
{
pass->setAlphaRejectFunction(CMPF_GREATER_EQUAL);
pass->setAlphaRejectValue(result.second);
}
else
{ {
// Enable transparency // Enable transparency
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
//pass->setDepthCheckEnabled(false); //pass->setDepthCheckEnabled(false);
pass->setDepthWriteEnabled(false); pass->setDepthWriteEnabled(false);
//std::cout << "alpha 237; material: " << name << " texName: " << texName << std::endl;
}
} }
else else
warn("Unhandled alpha setting for texture " + texName); 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 // 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->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha);
material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]);
material->setShininess(glossiness); 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 // 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); char suffix = name.at(name.length() - 2);
bool addAnim = true; bool addAnim = true;
bool hasAnim = false; bool hasAnim = false;
bool linkSkeleton = true;
//bool baddin = false; //bool baddin = false;
bNiTri = true; bNiTri = true;
if(name == "meshes\\base_anim.nif" || name == "meshes\\base_animkna.nif") if(name == "meshes\\base_anim.nif" || name == "meshes\\base_animkna.nif")
@ -1339,6 +1242,17 @@ void NIFLoader::loadResource(Resource *resource)
addAnim = false; 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)) 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 //Don't link on npc parts to eliminate redundant skeletons
//Will have to be changed later slightly for robes/skirts //Will have to be changed later slightly for robes/skirts
if(triname == "") if(linkSkeleton)
mesh->_notifySkeleton(mSkel); 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.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.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}/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}/black.png" "${DDIR}/black.png" COPYONLY)
configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY) configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY)
configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" 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}/mwgui.png" "${DDIR}/mwgui.png" COPYONLY)
configure_file("${SDIR}/openmw_images.xml" "${DDIR}/openmw_images.xml" COPYONLY) configure_file("${SDIR}/openmw_images.xml" "${DDIR}/openmw_images.xml" COPYONLY)
configure_file("${SDIR}/openmw_settings.xml" "${DDIR}/openmw_settings.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"> <MyGUI type="Resource">
<Resource type="ResourceImageSet" name="ArrowPointerImage"> <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" > <Index name="Pointer" >
<Frame point="0 0"/> <Frame point="0 0"/>
</Index> </Index>
</Group> </Group>
</Resource> </Resource>
<Resource type="ResourceImageSet" name="HResizePointerImage"> <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" > <Index name="Pointer" >
<Frame point="32 0"/> <Frame point="0 0"/>
</Index> </Index>
</Group> </Group>
</Resource> </Resource>
<Resource type="ResourceImageSet" name="VResizePointerImage"> <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" > <Index name="Pointer" >
<Frame point="0 32"/> <Frame point="0 0"/>
</Index> </Index>
</Group> </Group>
</Resource> </Resource>
<Resource type="ResourceImageSet" name="DResizePointerImage"> <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" > <Index name="Pointer" >
<Frame point="32 32"/> <Frame point="o o"/>
</Index> </Index>
</Group> </Group>
</Resource> </Resource>
<Resource type="ResourceImageSet" name="DResize2PointerImage"> <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" > <Index name="Pointer" >
<Frame point="64 32"/> <Frame point="0 0"/>
</Index> </Index>
</Group> </Group>
</Resource> </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] [Desktop Entry]
Version=0.11 Version=${OPENMW_VERSION}
Type=Application Type=Application
Name=OpenMW Launcher Name=OpenMW Launcher
GenericName=Role Playing Game GenericName=Role Playing Game

View file

@ -18,6 +18,32 @@ anisotropy = 4
# Number of texture mipmaps to generate # Number of texture mipmaps to generate
num mipmaps = 5 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] [HUD]
# FPS counter # FPS counter
# 0: not visible # 0: not visible
@ -64,15 +90,10 @@ num lights = 8
shader = true shader = true
rtt size = 512 rtt size = 512
reflect terrain = true reflect terrain = true
reflect statics = false reflect statics = false
reflect small statics = false reflect small statics = false
reflect actors = false
reflect actors = true
reflect misc = false reflect misc = false
# Enable underwater effect. It is not resource intensive, so only disable it if you have problems. # 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 technique
{ {
scheme Map scheme Fallback
pass pass
{ {
cull_hardware none 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 // manager before the main gui system itself, otherwise the main
// object will get the chance to spit out a few messages before we // object will get the chance to spit out a few messages before we
// can able to disable it. // can able to disable it.
/// \todo - can't avoid this with MyGUI 3.2?
std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME); std::string theLogFile = std::string(MYGUI_PLATFORM_LOG_FILENAME);
if(!logDir.empty()) 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. // Set up OGRE platform. We might make this more generic later.
mPlatform = new OgrePlatform(); mPlatform = new OgrePlatform();
LogManager::getInstance().setSTDOutputEnabled(logging);
mPlatform->initialise(wnd, mgr, "General", theLogFile); mPlatform->initialise(wnd, mgr, "General", theLogFile);
LogManager::getInstance().setSTDOutputEnabled(logging);
// Create GUI // Create GUI
mGui = new 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 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. 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) License: GPL (see GPL3.txt for more information)
Website: http://www.openmw.org Website: http://www.openmw.org
@ -64,8 +64,6 @@ Allowed options:
--start arg (=Beshara) set initial cell --start arg (=Beshara) set initial cell
--master arg master file(s) --master arg master file(s)
--plugin arg plugin 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 --anim-verbose [=arg(=1)] (=0) output animation indices files
--debug [=arg(=1)] (=0) debug mode --debug [=arg(=1)] (=0) debug mode
--nosound [=arg(=1)] (=0) disable all sounds --nosound [=arg(=1)] (=0) disable all sounds
@ -90,11 +88,13 @@ Allowed options:
win1252 - Western European (Latin) alphabet, win1252 - Western European (Latin) alphabet,
used by default used by default
--report-focus [=arg(=1)] (=0) write name of focussed object to cout --report-focus [=arg(=1)] (=0) write name of focussed object to cout
--fallback arg fallback values
CREDITS CREDITS
Current Developers: Current Developers:
Aleksandar Jovanov
Alexander “Ace” Olofsson Alexander “Ace” Olofsson
athile athile
BrotherBrick BrotherBrick
@ -133,6 +133,36 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil
CHANGELOG 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 0.13.0
Bug #145: Fixed sound problems after cell change Bug #145: Fixed sound problems after cell change