Merge branch 'master' into physicsaedra2

Conflicts:
	apps/openmw/mwworld/player.cpp
actorid
scrawl 13 years ago
commit f2fae770d4

@ -97,6 +97,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
@ -231,6 +232,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
@ -312,6 +316,7 @@ if(DPKG_PROGRAM)
#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")

@ -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 mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells
) )
# Main executable # Main executable

@ -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(),
@ -361,12 +370,17 @@ void OMW::Engine::go()
addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "mygui");
addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "water");
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);

@ -61,6 +61,10 @@ namespace MWClass
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]);
for (std::vector<std::string>::const_iterator iter (ref->base->spells.list.begin());
iter!=ref->base->spells.list.end(); ++iter)
data->mCreatureStats.mSpells.add (*iter);
// creature stats // creature stats
data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength);
data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence);

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

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

@ -66,6 +66,8 @@ namespace MWInput
A_QuickLoad, A_QuickLoad,
A_QuickMenu, A_QuickMenu,
A_GameMenu, A_GameMenu,
A_ToggleWeapon,
A_ToggleSpell,
A_LAST // Marker for the last item A_LAST // Marker for the last item
}; };
@ -87,6 +89,38 @@ namespace MWInput
/* InputImpl Methods */ /* InputImpl Methods */
void toggleSpell()
{
DrawState state = player.getDrawState();
if(state == DrawState_Weapon || state == DrawState_Nothing)
{
player.setDrawState(DrawState_Spell);
std::cout << "Player has now readied his hands for spellcasting!\n";
}
else
{
player.setDrawState(DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n";
}
}
void toggleWeapon()
{
DrawState state = player.getDrawState();
if(state == DrawState_Spell || state == DrawState_Nothing)
{
player.setDrawState(DrawState_Weapon);
std::cout << "Player is now drawing his weapon.\n";
}
else
{
player.setDrawState(DrawState_Nothing);
std::cout << "Player does not have any kind of attack ready now.\n";
}
}
void screenshot() void screenshot()
{ {
mEngine.screenshot(); mEngine.screenshot();
@ -198,7 +232,10 @@ namespace MWInput
"Auto Move"); "Auto Move");
disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this), disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this),
"Toggle Walk/Run"); "Toggle Walk/Run");
disp->funcs.bind(A_ToggleWeapon,boost::bind(&InputImpl::toggleWeapon,this),
"Draw Weapon");
disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this),
"Ready hands");
// Add the exit listener // Add the exit listener
ogre.getRoot()->addFrameListener(&exit); ogre.getRoot()->addFrameListener(&exit);
@ -243,6 +280,8 @@ namespace MWInput
disp->bind(A_AutoMove, KC_Z); disp->bind(A_AutoMove, KC_Z);
disp->bind(A_ToggleSneak, KC_X); disp->bind(A_ToggleSneak, KC_X);
disp->bind(A_ToggleWalk, KC_C); disp->bind(A_ToggleWalk, KC_C);
disp->bind(A_ToggleWeapon,KC_F);
disp->bind(A_ToggleSpell,KC_R);
// 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.

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

@ -0,0 +1,11 @@
#ifndef GAME_MWMECHANICS_DRAWSTATE_H
#define GAME_MWMECHANICS_DRAWSTATE_H
enum DrawState
{
DrawState_Weapon = 0,
DrawState_Spell = 1,
DrawState_Nothing = 2,
};
#endif

@ -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());
iter!=creatureStats.mAbilities.end(); ++iter)
{
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter);
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
iter!=spell->effects.list.end(); ++iter)
{
if (iter->range==0) // self
{
EffectParam param;
param.mMagnitude = iter->magnMax; // TODO calculate magnitude
now.add (EffectKey (*iter), param);
}
}
}
// TODO add effects from other spell types, active spells and equipment /// \todo add effects from active spells and equipment
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);

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

@ -2,14 +2,19 @@
#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"
namespace MWMechanics 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
{ {
@ -24,9 +29,10 @@ namespace MWMechanics
bool mRun; bool mRun;
bool mSneak; bool mSneak;
bool mCombat; bool mCombat;
DrawState mDrawState;
NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false),
mCombat (false) {} mCombat (false) , mDrawState(DrawState_Nothing) {}
}; };
} }

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

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

@ -1,4 +1,5 @@
#include "creatureanimation.hpp" #include "creatureanimation.hpp"
#include "renderconst.hpp"
#include "../mwworld/world.hpp" #include "../mwworld/world.hpp"
@ -20,6 +21,28 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, MWWorld::Environme
std::string meshNumbered = mesh + getUniqueID(mesh) + ">|"; std::string meshNumbered = mesh + getUniqueID(mesh) + ">|";
NifOgre::NIFLoader::load(meshNumbered); NifOgre::NIFLoader::load(meshNumbered);
base = mRend.getScene()->createEntity(meshNumbered); base = mRend.getScene()->createEntity(meshNumbered);
base->setVisibilityFlags(RV_Actors);
bool transparent = false;
for (unsigned int i=0; i<base->getNumSubEntities(); ++i)
{
Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
}
}
}
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
std::string meshZero = mesh + "0000>|"; std::string meshZero = mesh + "0000>|";
if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){ if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){

@ -4,6 +4,7 @@
#include "../mwworld/environment.hpp" #include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp" #include "../mwworld/world.hpp"
#include "../mwgui/window_manager.hpp" #include "../mwgui/window_manager.hpp"
#include "renderconst.hpp"
#include <OgreOverlayManager.h> #include <OgreOverlayManager.h>
#include <OgreMaterialManager.h> #include <OgreMaterialManager.h>
@ -223,7 +224,10 @@ void LocalMap::render(const float x, const float y,
vp->setOverlaysEnabled(false); vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setBackgroundColour(ColourValue(0, 0, 0));
//vp->setVisibilityMask( ... ); vp->setVisibilityMask(RV_Map);
// use fallback techniques without shadows and without mrt
vp->setMaterialScheme("Fallback");
rtt->update(); rtt->update();

@ -1,5 +1,6 @@
#include "npcanimation.hpp" #include "npcanimation.hpp"
#include "../mwworld/world.hpp" #include "../mwworld/world.hpp"
#include "renderconst.hpp"
using namespace Ogre; using namespace Ogre;
@ -65,6 +66,27 @@ 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);
bool transparent = false;
for (unsigned int i=0; i<base->getNumSubEntities(); ++i)
{
Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
}
}
}
base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones 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

@ -4,6 +4,7 @@
#include <components/nifogre/ogre_nif_loader.hpp> #include <components/nifogre/ogre_nif_loader.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "renderconst.hpp"
using namespace MWRender; using namespace MWRender;
@ -114,17 +115,49 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
bounds.scale(insert->getScale()); bounds.scale(insert->getScale());
mBounds[ptr.getCell()].merge(bounds); mBounds[ptr.getCell()].merge(bounds);
bool transparent = false;
for (unsigned int i=0; i<ent->getNumSubEntities(); ++i)
{
Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial();
Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator();
while (techIt.hasMoreElements())
{
Ogre::Technique* tech = techIt.getNext();
Ogre::Technique::PassIterator passIt = tech->getPassIterator();
while (passIt.hasMoreElements())
{
Ogre::Pass* pass = passIt.getNext();
if (pass->getDepthWriteEnabled() == false)
transparent = true;
}
}
}
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects"))
{ {
insert->attachObject(ent); insert->attachObject(ent);
ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); /// \todo config value ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0);
ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc);
ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
} }
else else
{ {
Ogre::StaticGeometry* sg = 0; Ogre::StaticGeometry* sg = 0;
if (small) /* if (transparent)
{
if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end())
{
uniqueID = uniqueID +1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometryAlpha[ptr.getCell()] = sg;
}
else
sg = mStaticGeometryAlpha[ptr.getCell()];
}
else*/ if (small)
{ {
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
{ {
@ -132,7 +165,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometrySmall[ptr.getCell()] = sg; mStaticGeometrySmall[ptr.getCell()] = sg;
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); /// \todo config value sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
} }
else else
sg = mStaticGeometrySmall[ptr.getCell()]; sg = mStaticGeometrySmall[ptr.getCell()];
@ -160,6 +193,12 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics);
sg->setCastShadows(true);
sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main);
mRenderer.getScene()->destroyEntity(ent); mRenderer.getScene()->destroyEntity(ent);
} }
} }
@ -253,6 +292,13 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
mRenderer.getScene()->destroyStaticGeometry (sg); mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0; sg = 0;
} }
/*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end())
{
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store];
mStaticGeometryAlpha.erase(store);
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}*/
if(mBounds.find(store) != mBounds.end()) if(mBounds.find(store) != mBounds.end())
mBounds.erase(store); mBounds.erase(store);
@ -270,6 +316,11 @@ void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
sg->build(); sg->build();
} }
/*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end())
{
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell];
sg->build();
}*/
} }
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)

@ -15,6 +15,7 @@ class Objects{
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes; std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry; std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall; std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
//std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometryAlpha;
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds; std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
std::vector<std::string> mLights; std::vector<std::string> mLights;
Ogre::SceneNode* mMwRoot; Ogre::SceneNode* mMwRoot;

@ -1,4 +1,5 @@
#include "occlusionquery.hpp" #include "occlusionquery.hpp"
#include "renderconst.hpp"
#include <OgreRenderSystem.h> #include <OgreRenderSystem.h>
#include <OgreRoot.h> #include <OgreRoot.h>
@ -40,9 +41,6 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
return; return;
} }
// This means that everything up to RENDER_QUEUE_MAIN can occlude the objects that are tested
const int queue = RENDER_QUEUE_MAIN+1;
MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting"); MaterialPtr matBase = MaterialManager::getSingleton().getByName("BaseWhiteNoLighting");
MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels"); MaterialPtr matQueryArea = matBase->clone("QueryTotalPixels");
matQueryArea->setDepthWriteEnabled(false); matQueryArea->setDepthWriteEnabled(false);
@ -62,25 +60,28 @@ 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");
mBBQueryTotal->setRenderQueueGroup(queue+1); mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1);
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");
mBBQueryVisible->setRenderQueueGroup(queue+1); mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1);
mBBNodeReal->attachObject(mBBQueryVisible); mBBNodeReal->attachObject(mBBQueryVisible);
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");
mBBQuerySingleObject->setRenderQueueGroup(queue); mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery);
mObjectNode->attachObject(mBBQuerySingleObject); mObjectNode->attachObject(mBBQuerySingleObject);
mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderObjectListener(this);
@ -153,7 +154,7 @@ void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocati
* this can happen for example if the object that is tested is outside of the view frustum * this can happen for example if the object that is tested is outside of the view frustum
* to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually * to prevent this, check if the queries have been performed after everything has been rendered and if not, start them manually
*/ */
if (queueGroupId == RENDER_QUEUE_SKIES_LATE) if (queueGroupId == RQG_SkiesLate)
{ {
if (mWasVisible == false && mDoQuery) if (mWasVisible == false && mDoQuery)
{ {

@ -0,0 +1,62 @@
#ifndef GAME_RENDER_CONST_H
#define GAME_RENDER_CONST_H
#include <OgreRenderQueue.h>
namespace MWRender
{
// Render queue groups
enum RenderQueueGroups
{
// Sky early (atmosphere, clouds, moons)
RQG_SkiesEarly = Ogre::RENDER_QUEUE_SKIES_EARLY,
RQG_Main = Ogre::RENDER_QUEUE_MAIN,
RQG_Water = Ogre::RENDER_QUEUE_7+1,
RQG_Alpha = Ogre::RENDER_QUEUE_MAIN,
RQG_UnderWater = Ogre::RENDER_QUEUE_7+1,
RQG_OcclusionQuery = Ogre::RENDER_QUEUE_8,
// Sky late (sun & sun flare)
RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE
};
// Visibility flags
enum VisibilityFlags
{
// Terrain
RV_Terrain = 1,
// Statics (e.g. trees, houses)
RV_Statics = 2,
// Small statics
RV_StaticsSmall = 4,
// Water
RV_Water = 8,
// Actors (player, npcs, creatures)
RV_Actors = 16,
// Misc objects (containers, dynamic objects)
RV_Misc = 32,
RV_Sky = 64,
// Sun glare (not visible in reflection)
RV_Glare = 128,
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water,
/// \todo markers (normally hidden)
};
}
#endif

@ -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,11 @@ 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;
//The fog type must be set before any terrain objects are created as if the //The fog type must be set before any terrain objects are created as if the
//fog type is set to FOG_NONE then the initially created terrain won't have any fog //fog type is set to FOG_NONE then the initially created terrain won't have any fog
@ -39,14 +43,34 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
std::string filter = Settings::Manager::getString("texture filtering", "General"); std::string filter = Settings::Manager::getString("texture filtering", "General");
if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; if (filter == "anisotropic") tfo = TFO_ANISOTROPIC;
else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "trilinear") tfo = TFO_TRILINEAR;
else /* if (filter == "bilinear") */ tfo = TFO_BILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR;
else if (filter == "none") tfo = TFO_NONE;
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
MaterialManager::getSingleton().setDefaultAnisotropy(Settings::Manager::getInt("anisotropy", "General")); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
// Load resources // Load resources
ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
// disable unsupported effects
const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
if (caps->getNumMultiRenderTargets() < 2)
Settings::Manager::setBool("shader", "Water", false);
// note that the order is important here
if (useMRT())
{
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbuffer");
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true);
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "Underwater");
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "gbufferFinalizer");
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true);
}
else
{
CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "UnderwaterNoMRT");
}
// Turn the entire scene (represented by the 'root' node) -90 // Turn the entire scene (represented by the 'root' node) -90
// degrees around the x axis. This makes Z go upwards, and Y go into // degrees around the x axis. This makes Z go upwards, and Y go into
// the screen (when x is to the right.) This is the orientation that // the screen (when x is to the right.) This is the orientation that
@ -64,13 +88,17 @@ 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);
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
mWater = 0;
mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode);
mSun = 0; mSun = 0;
@ -122,8 +150,7 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store)
void RenderingManager::removeWater () void RenderingManager::removeWater ()
{ {
if(mWater){ if(mWater){
delete mWater; mWater->setActive(false);
mWater = 0;
} }
} }
@ -139,6 +166,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store)
mDebugging->cellAdded(store); mDebugging->cellAdded(store);
if (store->cell->isExterior()) if (store->cell->isExterior())
mTerrainManager->cellAdded(store); mTerrainManager->cellAdded(store);
waterAdded(store);
} }
void RenderingManager::addObject (const MWWorld::Ptr& ptr){ void RenderingManager::addObject (const MWWorld::Ptr& ptr){
@ -195,11 +223,10 @@ void RenderingManager::update (float duration){
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
if(store->cell->data.flags & store->cell->HasWater){ if(store->cell->data.flags & store->cell->HasWater){
if(mWater == 0) if(mWater == 0)
mWater = new MWRender::Water(mRendering.getCamera(), store->cell); mWater = new MWRender::Water(mRendering.getCamera(), mSkyManager, store->cell);
else else
mWater->changeCell(store->cell); mWater->changeCell(store->cell);
//else mWater->setActive(true);
} }
else else
removeWater(); removeWater();
@ -263,11 +290,25 @@ bool RenderingManager::toggleRenderMode(int mode)
{ {
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
{ {
// disable compositors
if (useMRT())
{
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false);
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false);
}
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
return true; return true;
} }
else else
{ {
// re-enable compositors
if (useMRT())
{
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true);
CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true);
}
mRendering.getCamera()->setPolygonMode(PM_SOLID); mRendering.getCamera()->setPolygonMode(PM_SOLID);
return false; return false;
} }
@ -276,23 +317,29 @@ bool RenderingManager::toggleRenderMode(int mode)
void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell) void RenderingManager::configureFog(ESMS::CellStore<MWWorld::RefData> &mCell)
{ {
Ogre::ColourValue color; Ogre::ColourValue color;
color.setAsABGR (mCell.cell->ambi.fog); color.setAsABGR (mCell.cell->ambi.fog);
configureFog(mCell.cell->ambi.fogDensity, color); configureFog(mCell.cell->ambi.fogDensity, color);
} }
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
{ {
float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance");
float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high);
float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); mRendering.getCamera()->setFarClipDistance ( max / density );
mRendering.getViewport()->setBackgroundColour (colour);
mRendering.getCamera()->setFarClipDistance ( max / density ); CompositorInstance* inst = CompositorManager::getSingleton().getCompositorChain(mRendering.getViewport())->getCompositor("gbuffer");
mRendering.getViewport()->setBackgroundColour (colour); if (inst != 0)
inst->getCompositor()->getTechnique(0)->getTargetPass(0)->getPass(0)->setClearColour(colour);
if (mWater)
mWater->setViewportBackground(colour);
} }
@ -319,41 +366,43 @@ void RenderingManager::setAmbientMode()
void RenderingManager::configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell) void RenderingManager::configureAmbient(ESMS::CellStore<MWWorld::RefData> &mCell)
{ {
mAmbientColor.setAsABGR (mCell.cell->ambi.ambient); mAmbientColor.setAsABGR (mCell.cell->ambi.ambient);
setAmbientMode(); setAmbientMode();
// Create a "sun" that shines light downwards. It doesn't look // Create a "sun" that shines light downwards. It doesn't look
// completely right, but leave it for now. // completely right, but leave it for now.
if(!mSun) if(!mSun)
{ {
mSun = mRendering.getScene()->createLight(); mSun = mRendering.getScene()->createLight();
} }
Ogre::ColourValue colour; Ogre::ColourValue colour;
colour.setAsABGR (mCell.cell->ambi.sunlight); colour.setAsABGR (mCell.cell->ambi.sunlight);
mSun->setDiffuseColour (colour); mSun->setDiffuseColour (colour);
mSun->setType(Ogre::Light::LT_DIRECTIONAL); mSun->setType(Ogre::Light::LT_DIRECTIONAL);
mSun->setDirection(0,-1,0); mSun->setDirection(0,-1,0);
} }
// Switch through lighting modes. // Switch through lighting modes.
void RenderingManager::toggleLight() void RenderingManager::toggleLight()
{ {
if (mAmbientMode==2) if (mAmbientMode==2)
mAmbientMode = 0; mAmbientMode = 0;
else else
++mAmbientMode; ++mAmbientMode;
switch (mAmbientMode) switch (mAmbientMode)
{ {
case 0: std::cout << "Setting lights to normal\n"; break; case 0: std::cout << "Setting lights to normal\n"; break;
case 1: std::cout << "Turning the lights up\n"; break; case 1: std::cout << "Turning the lights up\n"; break;
case 2: std::cout << "Turning the lights to full\n"; break; case 2: std::cout << "Turning the lights to full\n"; break;
} }
setAmbientMode(); setAmbientMode();
} }
void RenderingManager::checkUnderwater(){ void RenderingManager::checkUnderwater()
if(mWater){ {
if(mWater)
{
mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y ); mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y );
} }
} }
@ -371,7 +420,9 @@ 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);
mTerrainManager->setDiffuse(colour); mTerrainManager->setDiffuse(colour);
} }
@ -383,12 +434,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)
@ -428,4 +488,14 @@ void RenderingManager::enableLights()
mObjects.enableLights(); mObjects.enableLights();
} }
const bool RenderingManager::useMRT()
{
return Settings::Manager::getBool("shader", "Water");
}
Shadows* RenderingManager::getShadows()
{
return mShadows;
}
} // namespace } // namespace

@ -25,17 +25,12 @@
#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
{ {
class Camera;
class Viewport;
class SceneManager; class SceneManager;
class SceneNode; class SceneNode;
class RaySceneQuery;
class Quaternion; class Quaternion;
class Vector3; class Vector3;
} }
@ -48,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 {
@ -84,6 +82,8 @@ class RenderingManager: private RenderingInterface {
void removeWater(); void removeWater();
static const bool useMRT();
void preCellChange (MWWorld::Ptr::CellStore* store); void preCellChange (MWWorld::Ptr::CellStore* store);
///< this event is fired immediately before changing cell ///< this event is fired immediately before changing cell
@ -115,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 ();
@ -150,6 +152,8 @@ class RenderingManager: private RenderingInterface {
void setAmbientMode(); void setAmbientMode();
bool mSunEnabled;
SkyManager* mSkyManager; SkyManager* mSkyManager;
OcclusionQuery* mOcclusionQuery; OcclusionQuery* mOcclusionQuery;
@ -181,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;
}; };
} }

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

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

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

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

@ -12,7 +12,8 @@
#include "../mwworld/environment.hpp" #include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp" #include "../mwworld/world.hpp"
#include "occlusionquery.hpp" #include "renderconst.hpp"
#include "renderingmanager.hpp"
using namespace MWRender; using namespace MWRender;
using namespace Ogre; using namespace Ogre;
@ -60,6 +61,11 @@ Vector3 BillboardObject::getPosition() const
return Vector3(p.x, -p.z, p.y); return Vector3(p.x, -p.z, p.y);
} }
void BillboardObject::setVisibilityFlags(int flags)
{
mBBSet->setVisibilityFlags(flags);
}
void BillboardObject::setColour(const ColourValue& pColour) void BillboardObject::setColour(const ColourValue& pColour)
{ {
mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour); mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour);
@ -89,13 +95,14 @@ void BillboardObject::init(const String& textureName,
/// \todo These billboards are not 100% correct, might want to revisit them later /// \todo These billboards are not 100% correct, might want to revisit them later
mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1); mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1);
mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize); mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize);
mBBSet->setRenderQueueGroup(RENDER_QUEUE_MAIN+2);
mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON); mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON);
mBBSet->setCommonDirection( -position.normalisedCopy() ); mBBSet->setCommonDirection( -position.normalisedCopy() );
mBBSet->setVisibilityFlags(RV_Sky);
mNode = rootNode->createChildSceneNode(); mNode = rootNode->createChildSceneNode();
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();
@ -109,6 +116,65 @@ void BillboardObject::init(const String& textureName,
p->createTextureUnitState(textureName); p->createTextureUnitState(textureName);
mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount));
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
HighLevelGpuProgramPtr vshader;
if (mgr.resourceExists("BBO_VP"))
vshader = mgr.getByName("BBO_VP");
else
vshader = mgr.createProgram("BBO_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM);
vshader->setParameter("profiles", "vs_2_x arbvp1");
vshader->setParameter("entry_point", "main_vp");
StringUtil::StrStreamType outStream;
outStream <<
"void main_vp( \n"
" float4 position : POSITION, \n"
" in float2 uv : TEXCOORD0, \n"
" out float2 oUV : TEXCOORD0, \n"
" out float4 oPosition : POSITION, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oUV = uv; \n"
" oPosition = mul( worldViewProj, position ); \n"
"}";
vshader->setSource(outStream.str());
vshader->load();
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
HighLevelGpuProgramPtr fshader;
if (mgr.resourceExists("BBO_FP"))
fshader = mgr.getByName("BBO_FP");
else
fshader = mgr.createProgram("BBO_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM);
fshader->setParameter("profiles", "ps_2_x arbfp1");
fshader->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType outStream2;
outStream2 <<
"void main_fp( \n"
" in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n";
if (RenderingManager::useMRT()) outStream2 <<
" out float4 oColor1 : COLOR1, \n";
outStream2 <<
" uniform sampler2D texture : TEXUNIT0, \n"
" uniform float4 diffuse, \n"
" uniform float4 emissive \n"
") \n"
"{ \n"
" float4 tex = tex2D(texture, uv); \n"
" oColor = float4(emissive.xyz,1) * tex * float4(1,1,1,diffuse.a); \n";
if (RenderingManager::useMRT()) outStream2 <<
" oColor1 = float4(1, 0, 0, 1); \n";
outStream2 <<
"}";
fshader->setSource(outStream2.str());
fshader->load();
fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR);
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
bodyCount++; bodyCount++;
} }
@ -157,7 +223,10 @@ Moon::Moon( const String& textureName,
outStream2 << outStream2 <<
"void main_fp( \n" "void main_fp( \n"
" in float2 uv : TEXCOORD0, \n" " in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n" " out float4 oColor : COLOR, \n";
if (RenderingManager::useMRT()) outStream2 <<
" out float4 oColor1 : COLOR1, \n";
outStream2 <<
" uniform sampler2D texture : TEXUNIT0, \n" " uniform sampler2D texture : TEXUNIT0, \n"
" uniform float4 skyColour, \n" " uniform float4 skyColour, \n"
" uniform float4 diffuse, \n" " uniform float4 diffuse, \n"
@ -165,7 +234,10 @@ Moon::Moon( const String& textureName,
") \n" ") \n"
"{ \n" "{ \n"
" float4 tex = tex2D(texture, uv); \n" " float4 tex = tex2D(texture, uv); \n"
" oColor = float4(emissive.xyz,1) * tex; \n" " oColor = float4(emissive.xyz,1) * tex; \n";
if (RenderingManager::useMRT()) outStream2 <<
" oColor1 = float4(1, 0, 0, 1); \n";
outStream2 <<
// use a circle for the alpha (compute UV distance to center) // use a circle for the alpha (compute UV distance to center)
// looks a bit bad because its not filtered on the edges, // looks a bit bad because its not filtered on the edges,
// but it's cheaper than a seperate alpha texture. // but it's cheaper than a seperate alpha texture.
@ -358,15 +430,17 @@ void SkyManager::create()
mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode); mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode);
mSecunda->setType(Moon::Type_Secunda); mSecunda->setType(Moon::Type_Secunda);
mSecunda->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+4); mSecunda->setRenderQueue(RQG_SkiesEarly+4);
mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode); mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode);
mMasser->setRenderQueue(RENDER_QUEUE_SKIES_EARLY+3); mMasser->setRenderQueue(RQG_SkiesEarly+3);
mMasser->setType(Moon::Type_Masser); mMasser->setType(Moon::Type_Masser);
mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode); mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode);
mSun->setRenderQueue(RQG_SkiesEarly+4);
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode); mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode);
mSunGlare->setRenderQueue(RENDER_QUEUE_SKIES_LATE); mSunGlare->setRenderQueue(RQG_SkiesLate);
mSunGlare->setVisibilityFlags(RV_Glare);
HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton();
@ -375,7 +449,9 @@ void SkyManager::create()
/// \todo sky_night_02.nif (available in Bloodmoon) /// \todo sky_night_02.nif (available in Bloodmoon)
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif");
night1_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+1); night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1);
night1_ent->setVisibilityFlags(RV_Sky);
night1_ent->setCastShadows(false);
mAtmosphereNight = mRootNode->createChildSceneNode(); mAtmosphereNight = mRootNode->createChildSceneNode();
mAtmosphereNight->attachObject(night1_ent); mAtmosphereNight->attachObject(night1_ent);
@ -413,7 +489,10 @@ void SkyManager::create()
outStream5 << outStream5 <<
"void main_fp( \n" "void main_fp( \n"
" in float2 uv : TEXCOORD0, \n" " in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n" " out float4 oColor : COLOR, \n";
if (RenderingManager::useMRT()) outStream5 <<
" out float4 oColor1 : COLOR1, \n";
outStream5 <<
" in float fade : TEXCOORD1, \n" " in float fade : TEXCOORD1, \n"
" uniform sampler2D texture : TEXUNIT0, \n" " uniform sampler2D texture : TEXUNIT0, \n"
" uniform float opacity, \n" " uniform float opacity, \n"
@ -421,7 +500,10 @@ void SkyManager::create()
" uniform float4 emissive \n" " uniform float4 emissive \n"
") \n" ") \n"
"{ \n" "{ \n"
" oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n" " oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n";
if (RenderingManager::useMRT()) outStream5 <<
" oColor1 = float4(1, 0, 0, 1); \n";
outStream5 <<
"}"; "}";
stars_fp->setSource(outStream5.str()); stars_fp->setSource(outStream5.str());
stars_fp->load(); stars_fp->load();
@ -445,10 +527,12 @@ 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);
atmosphere_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly);
atmosphere_ent->setVisibilityFlags(RV_Sky);
mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay = mRootNode->createChildSceneNode();
mAtmosphereDay->attachObject(atmosphere_ent); mAtmosphereDay->attachObject(atmosphere_ent);
mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial();
@ -466,29 +550,56 @@ void SkyManager::create()
" float4 position : POSITION, \n" " float4 position : POSITION, \n"
" in float4 color : COLOR, \n" " in float4 color : COLOR, \n"
" out float4 oPosition : POSITION, \n" " out float4 oPosition : POSITION, \n"
" out float4 oColor : COLOR, \n" " out float4 oVertexColor : TEXCOORD0, \n"
" uniform float4 emissive, \n"
" uniform float4x4 worldViewProj \n" " uniform float4x4 worldViewProj \n"
") \n" ") \n"
"{ \n" "{ \n"
" oPosition = mul( worldViewProj, position ); \n" " oPosition = mul( worldViewProj, position ); \n"
" oColor = color * emissive; \n" " oVertexColor = color; \n"
"}"; "}";
vshader->setSource(outStream.str()); vshader->setSource(outStream.str());
vshader->load(); vshader->load();
vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
vshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName());
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram("");
HighLevelGpuProgramPtr fshader = mgr.createProgram("Atmosphere_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
"cg", GPT_FRAGMENT_PROGRAM);
fshader->setParameter("profiles", "ps_2_x arbfp1");
fshader->setParameter("entry_point", "main_fp");
StringUtil::StrStreamType _outStream;
_outStream <<
"void main_fp( \n"
" in float4 iVertexColor : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n";
if (RenderingManager::useMRT()) _outStream <<
" out float4 oColor1 : COLOR1, \n";
_outStream <<
" uniform float4 emissive \n"
") \n"
"{ \n"
" oColor = iVertexColor * emissive; \n";
if (RenderingManager::useMRT()) _outStream <<
" oColor1 = float4(1, 0, 0, 1); \n";
_outStream <<
"}";
fshader->setSource(_outStream.str());
fshader->load();
fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR);
mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName());
// Clouds // Clouds
NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif");
Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif"); Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif");
clouds_ent->setRenderQueueGroup(RENDER_QUEUE_SKIES_EARLY+5); clouds_ent->setVisibilityFlags(RV_Sky);
clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5);
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,
@ -525,8 +636,11 @@ void SkyManager::create()
outStream2 << outStream2 <<
"void main_fp( \n" "void main_fp( \n"
" in float2 uv : TEXCOORD0, \n" " in float2 uv : TEXCOORD0, \n"
" out float4 oColor : COLOR, \n"
" in float4 color : TEXCOORD1, \n" " in float4 color : TEXCOORD1, \n"
" out float4 oColor : COLOR, \n";
if (RenderingManager::useMRT()) outStream2 <<
" out float4 oColor1 : COLOR1, \n";
outStream2 <<
" uniform sampler2D texture : TEXUNIT0, \n" " uniform sampler2D texture : TEXUNIT0, \n"
" uniform sampler2D secondTexture : TEXUNIT1, \n" " uniform sampler2D secondTexture : TEXUNIT1, \n"
" uniform float transitionFactor, \n" " uniform float transitionFactor, \n"
@ -538,7 +652,10 @@ void SkyManager::create()
"{ \n" "{ \n"
" uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction " uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction
" float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n" " float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n"
" oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n" " oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n";
if (RenderingManager::useMRT()) outStream2 <<
" oColor1 = float4(1, 0, 0, 1); \n";
outStream2 <<
"}"; "}";
mCloudFragmentShader->setSource(outStream2.str()); mCloudFragmentShader->setSource(outStream2.str());
mCloudFragmentShader->load(); mCloudFragmentShader->load();
@ -564,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;
@ -653,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));
} }
@ -734,7 +855,8 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
strength = 1.f; strength = 1.f;
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength); mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
mSun->setVisibility(mGlareFade >= 0.5 ? weather.mGlareView * mGlareFade * strength : 0);
mSun->setVisibility(weather.mGlareView * strength);
mAtmosphereNight->setVisible(weather.mNight && mEnabled); mAtmosphereNight->setVisible(weather.mNight && mEnabled);
} }
@ -813,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);
} }
@ -837,3 +961,18 @@ Ogre::SceneNode* SkyManager::getSunNode()
if (!mCreated) return 0; if (!mCreated) return 0;
return mSun->getNode(); return mSun->getNode();
} }
void SkyManager::setSkyPosition(const Ogre::Vector3& position)
{
mRootNode->_setDerivedPosition(position);
}
void SkyManager::resetSkyPosition()
{
mRootNode->setPosition(0,0,0);
}
void SkyManager::scaleSky(float scale)
{
mRootNode->setScale(scale, scale, scale);
}

@ -36,24 +36,25 @@ namespace MWRender
BillboardObject(); BillboardObject();
virtual ~BillboardObject() {} virtual ~BillboardObject() {}
void setColour(const Ogre::ColourValue& pColour); void setColour(const Ogre::ColourValue& pColour);
void setPosition(const Ogre::Vector3& pPosition); void setPosition(const Ogre::Vector3& pPosition);
void setVisible(const bool visible); void setVisible(const bool visible);
void setRenderQueue(unsigned int id); void setRenderQueue(unsigned int id);
void setVisibilityFlags(int flags);
void setSize(const float size); void setSize(const float size);
Ogre::Vector3 getPosition() const; Ogre::Vector3 getPosition() const;
void setVisibility(const float visibility); void setVisibility(const float visibility);
Ogre::SceneNode* getNode(); Ogre::SceneNode* getNode();
protected: protected:
virtual void init(const Ogre::String& textureName, virtual void init(const Ogre::String& textureName,
const float size, const float size,
const Ogre::Vector3& position, const Ogre::Vector3& position,
Ogre::SceneNode* rootNode); Ogre::SceneNode* rootNode);
Ogre::SceneNode* mNode; Ogre::SceneNode* mNode;
Ogre::MaterialPtr mMaterial; Ogre::MaterialPtr mMaterial;
Ogre::BillboardSet* mBBSet; Ogre::BillboardSet* mBBSet;
@ -71,9 +72,9 @@ namespace MWRender
const Ogre::Vector3& position, const Ogre::Vector3& position,
Ogre::SceneNode* rootNode Ogre::SceneNode* rootNode
); );
virtual ~Moon() {} virtual ~Moon() {}
enum Phase enum Phase
{ {
Phase_New = 0, Phase_New = 0,
@ -85,20 +86,20 @@ namespace MWRender
Phase_WaningHalf, Phase_WaningHalf,
Phase_WaningCrescent Phase_WaningCrescent
}; };
enum Type enum Type
{ {
Type_Masser = 0, Type_Masser = 0,
Type_Secunda Type_Secunda
}; };
void setPhase(const Phase& phase); void setPhase(const Phase& phase);
void setType(const Type& type); void setType(const Type& type);
void setSkyColour(const Ogre::ColourValue& colour); void setSkyColour(const Ogre::ColourValue& colour);
Phase getPhase() const; Phase getPhase() const;
unsigned int getPhaseInt() const; unsigned int getPhaseInt() const;
private: private:
Type mType; Type mType;
Phase mPhase; Phase mPhase;
@ -168,6 +169,10 @@ namespace MWRender
void setGlare(const float glare); void setGlare(const float glare);
Ogre::Vector3 getRealSunPos(); Ogre::Vector3 getRealSunPos();
void setSkyPosition(const Ogre::Vector3& position);
void resetSkyPosition();
void scaleSky(float scale);
private: private:
bool mCreated; bool mCreated;
@ -180,21 +185,21 @@ namespace MWRender
BillboardObject* mSunGlare; BillboardObject* mSunGlare;
Moon* mMasser; Moon* mMasser;
Moon* mSecunda; Moon* mSecunda;
Ogre::Viewport* mViewport; Ogre::Viewport* mViewport;
Ogre::SceneNode* mRootNode; Ogre::SceneNode* mRootNode;
Ogre::SceneManager* mSceneMgr; Ogre::SceneManager* mSceneMgr;
Ogre::SceneNode* mAtmosphereDay; Ogre::SceneNode* mAtmosphereDay;
Ogre::SceneNode* mAtmosphereNight; Ogre::SceneNode* mAtmosphereNight;
Ogre::MaterialPtr mCloudMaterial; Ogre::MaterialPtr mCloudMaterial;
Ogre::MaterialPtr mAtmosphereMaterial; Ogre::MaterialPtr mAtmosphereMaterial;
Ogre::MaterialPtr mStarsMaterials[7]; Ogre::MaterialPtr mStarsMaterials[7];
Ogre::HighLevelGpuProgramPtr mCloudFragmentShader; Ogre::HighLevelGpuProgramPtr mCloudFragmentShader;
// remember some settings so we don't have to apply them again if they didnt change // remember some settings so we don't have to apply them again if they didnt change
Ogre::String mClouds; Ogre::String mClouds;
Ogre::String mNextClouds; Ogre::String mNextClouds;
@ -204,17 +209,17 @@ namespace MWRender
float mStarsOpacity; float mStarsOpacity;
Ogre::ColourValue mCloudColour; Ogre::ColourValue mCloudColour;
Ogre::ColourValue mSkyColour; Ogre::ColourValue mSkyColour;
Ogre::Overlay* mThunderOverlay; Ogre::Overlay* mThunderOverlay;
Ogre::TextureUnitState* mThunderTextureUnit; Ogre::TextureUnitState* mThunderTextureUnit;
float mRemainingTransitionTime; float mRemainingTransitionTime;
float mGlare; // target float mGlare; // target
float mGlareFade; // actual float mGlareFade; // actual
void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType); void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType);
bool mEnabled; bool mEnabled;
bool mSunEnabled; bool mSunEnabled;
bool mMasserEnabled; bool mMasserEnabled;

@ -6,7 +6,9 @@
#include "terrainmaterial.hpp" #include "terrainmaterial.hpp"
#include "terrain.hpp" #include "terrain.hpp"
#include "renderconst.hpp"
#include "shadows.hpp"
#include <components/settings/settings.hpp>
using namespace Ogre; using namespace Ogre;
@ -15,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;
@ -47,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);
@ -162,6 +174,8 @@ namespace MWRender
x * numTextures, y * numTextures, x * numTextures, y * numTextures,
numTextures, numTextures,
indexes); indexes);
terrain->setVisibilityFlags(RV_Terrain);
terrain->setRenderQueueGroup(RQG_Main);
if ( land && land->landData->usingColours ) if ( land && land->landData->usingColours )
{ {

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

@ -37,6 +37,7 @@ THE SOFTWARE.
#include "OgreShadowCameraSetupPSSM.h" #include "OgreShadowCameraSetupPSSM.h"
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include "renderingmanager.hpp"
namespace Ogre namespace Ogre
{ {
@ -85,6 +86,7 @@ namespace Ogre
, mPSSM(0) , mPSSM(0)
, mDepthShadows(false) , mDepthShadows(false)
, mLowLodShadows(false) , mLowLodShadows(false)
, mShadowFar(1300)
{ {
} }
@ -101,6 +103,24 @@ namespace Ogre
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)
{ {
@ -461,6 +481,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);
@ -532,8 +553,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);
} }
} }
} }
@ -557,12 +578,16 @@ namespace Ogre
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);
} }
if (MWRender::RenderingManager::useMRT())
params->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE);
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);
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())
{ {
@ -728,7 +753,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;
@ -753,12 +778,7 @@ namespace Ogre
ret->unload(); ret->unload();
} }
if(prof->isLayerNormalMappingEnabled() || prof->isLayerParallaxMappingEnabled()) ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1");
ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1");
//else
//ret->setParameter("profiles", "ps_3_0 ps_2_0 fp30 arbfp1");
else // fp30 doesn't work (black terrain)
ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1");
ret->setParameter("entry_point", "main_fp"); ret->setParameter("entry_point", "main_fp");
return ret; return ret;
@ -791,9 +811,9 @@ namespace Ogre
outStream << outStream <<
"out float4 oPos : POSITION,\n" "out float4 oPos : POSITION,\n"
"out float4 oPosObj : TEXCOORD0 \n"; "out float4 oPosObj : COLOR \n";
uint texCoordSet = 1; uint texCoordSet = 0;
outStream << outStream <<
", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n"; ", out float4 oUVMisc : TEXCOORD" << texCoordSet++ <<" // xy = uv, z = camDepth\n";
@ -819,8 +839,8 @@ namespace Ogre
if (fog) if (fog)
{ {
outStream << outStream <<
", uniform float4 fogParams\n" ", uniform float4 fogParams\n";
", out float fogVal : COLOR\n"; //", out float fogVal : COLOR\n";
} }
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
@ -832,7 +852,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__);
} }
@ -917,10 +937,10 @@ namespace Ogre
outStream << outStream <<
"float4 main_fp(\n" "void main_fp(\n"
"float4 position : TEXCOORD0,\n"; "float4 position : COLOR,\n";
uint texCoordSet = 1; uint texCoordSet = 0;
outStream << outStream <<
"float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n"; "float4 uvMisc : TEXCOORD" << texCoordSet++ << ",\n";
@ -949,8 +969,8 @@ namespace Ogre
if (fog) if (fog)
{ {
outStream << outStream <<
"uniform float3 fogColour, \n" "uniform float3 fogColour, \n";
"float fogVal : COLOR,\n"; //"float fogVal : COLOR,\n";
} }
uint currentSamplerIdx = 0; uint currentSamplerIdx = 0;
@ -1034,12 +1054,20 @@ namespace Ogre
__FUNCTION__); __FUNCTION__);
} }
if (MWRender::RenderingManager::useMRT()) outStream <<
" , out float4 oColor : COLOR \n"
" , out float4 oColor1 : COLOR1 \n"
" , uniform float far \n";
else outStream <<
" , out float4 oColor : COLOR \n";
outStream << outStream <<
") : COLOR\n" ")\n"
"{\n" "{\n"
" float4 outputCol;\n" " float4 outputCol;\n"
" float shadow = 1.0;\n" " float shadow = 1.0;\n"
" float2 uv = uvMisc.xy;\n" " float2 uv = uvMisc.xy;\n"
" float fogVal = position.w; \n"
// base colour // base colour
" outputCol = float4(0,0,0,1);\n"; " outputCol = float4(0,0,0,1);\n";
@ -1241,19 +1269,25 @@ namespace Ogre
" oPos = mul(viewProjMatrix, worldPos);\n" " oPos = mul(viewProjMatrix, worldPos);\n"
" oUVMisc.xy = uv.xy;\n"; " oUVMisc.xy = uv.xy;\n";
outStream <<
" // pass cam depth\n"
" oUVMisc.z = oPos.z;\n";
bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP;
if (fog) if (fog)
{ {
if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR)
{ {
outStream << outStream <<
" fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n"; " float fogVal = saturate((oPos.z - fogParams.y) * fogParams.w);\n";
} }
else else
{ {
outStream << outStream <<
" fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n"; " float fogVal = saturate(1 / (exp(oPos.z * fogParams.x)));\n";
} }
outStream <<
" oPosObj.w = fogVal; \n";
} }
if (prof->isShadowingEnabled(tt, terrain)) if (prof->isShadowingEnabled(tt, terrain))
@ -1337,7 +1371,12 @@ namespace Ogre
} }
// Final return // Final return
outStream << " return outputCol;\n" outStream << " oColor = outputCol;\n";
if (MWRender::RenderingManager::useMRT()) outStream <<
" oColor1 = float4(uvMisc.z / far, 0, 0, 1); \n";
outStream
<< "}\n"; << "}\n";
} }
@ -1349,7 +1388,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"
@ -1362,28 +1401,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" " { \n"
" // 4-sample PCF \n" " shadowMapPos = shadowMapPos / shadowMapPos.w; \n"
" float2 uv = shadowMapPos.xy; \n"
" float shadow = 0.0; \n" " float3 o = float3(offset, -offset.x) * 0.3f; \n"
" float offset = (NUM_SHADOW_SAMPLES_1D/2 - 0.5) * SHADOW_FILTER_SCALE; \n" " // Note: We using 2x2 PCF. Good enough and is alot faster. \n"
" for (float y = -offset; y <= offset; y += SHADOW_FILTER_SCALE) \n" " float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n"
" for (float x = -offset; x <= offset; x += SHADOW_FILTER_SCALE) \n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n"
" { \n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n"
" float4 newUV = offsetSample(uv, float2(x, y), invShadowMapSize);\n" " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n"
" // manually project and assign derivatives \n" " return c / 4; \n"
" // to avoid gradient issues inside loops \n" " } \n";
" newUV = newUV / newUV.w; \n"
" float depth = tex2D(shadowMap, newUV.xy, 1, 1).x; \n"
" if (depth >= 1 || depth >= uv.z)\n"
" shadow += 1.0;\n"
" } \n"
" shadow /= SHADOW_SAMPLES; \n"
" return shadow; \n"
"} \n";
} }
else else
{ {
@ -1421,7 +1450,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"
@ -1443,7 +1472,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
{ {
@ -1505,20 +1534,12 @@ 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";
} }
} }
if (prof->getReceiveDynamicShadowsPSSM())
{
outStream <<
" // pass cam depth\n"
" oUVMisc.z = oPos.z;\n";
}
} }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsParams( void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsParams(
@ -1531,6 +1552,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();
@ -1547,7 +1570,7 @@ namespace Ogre
if (prof->getReceiveDynamicShadowsDepth()) if (prof->getReceiveDynamicShadowsDepth())
{ {
outStream << outStream <<
", uniform float inverseShadowmapSize" << i << " \n"; ", uniform float4 inverseShadowmapSize" << i << " \n";
} }
} }
@ -1582,7 +1605,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";
@ -1593,7 +1616,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
{ {
@ -1602,7 +1625,11 @@ namespace Ogre
} }
} }
outStream << outStream <<
" float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n"
" float fade = 1-((uvMisc.z - shadowFar_fadeStart.y) / fadeRange); \n"
" rtshadow = (uvMisc.z > shadowFar_fadeStart.x) ? 1 : ((uvMisc.z > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n"
" rtshadow = (1-(1-rtshadow)*0.6); \n" // make the shadow a little less intensive
" shadow = min(shadow, rtshadow);\n"; " shadow = min(shadow, rtshadow);\n";
} }

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

@ -1,50 +1,151 @@
#include "water.hpp" #include "water.hpp"
#include <components/settings/settings.hpp>
#include "sky.hpp"
#include "renderingmanager.hpp"
using namespace Ogre;
namespace MWRender namespace MWRender
{ {
Water::Water (Ogre::Camera *camera, const ESM::Cell* cell) : Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()),
mIsUnderwater(false) mIsUnderwater(false), mVisibilityFlags(0),
mReflectionTarget(0), mActive(1), mToggled(1)
{ {
mSky = sky;
try try
{ {
Ogre::CompositorManager::getSingleton().addCompositor(mViewport, "Water", -1); CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
} catch(...) {} } catch(...) {}
mTop = cell->water; mTop = cell->water;
mIsUnderwater = false; mIsUnderwater = false;
mWaterPlane = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0); mWaterPlane = Plane(Vector3::UNIT_Y, 0);
Ogre::MeshManager::getSingleton().createPlane("water", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,5, Ogre::Vector3::UNIT_Z); MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z);
mWater = mSceneManager->createEntity("water"); mWater = mSceneManager->createEntity("water");
mWater->setVisibilityFlags(RV_Water);
mWater->setRenderQueueGroup(RQG_Water);
mWater->setCastShadows(false);
mWater->setMaterialName("Examples/Water0"); mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water")
+ RV_Statics * Settings::Manager::getBool("reflect statics", "Water")
+ RV_StaticsSmall * Settings::Manager::getBool("reflect small statics", "Water")
+ RV_Actors * Settings::Manager::getBool("reflect actors", "Water")
+ RV_Misc * Settings::Manager::getBool("reflect misc", "Water")
+ RV_Sky;
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));
} }
mWaterNode->attachObject(mWater); mWaterNode->attachObject(mWater);
// Create rendertarget for reflection
int rttsize = Settings::Manager::getInt("rtt size", "Water");
TexturePtr tex;
if (Settings::Manager::getBool("shader", "Water"))
{
tex = TextureManager::getSingleton().createManual("WaterReflection",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_FLOAT16_RGBA, TU_RENDERTARGET);
RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
Viewport* vp = rtt->addViewport(mReflectionCamera);
vp->setOverlaysEnabled(false);
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
vp->setShadowsEnabled(false);
vp->setVisibilityMask( mVisibilityFlags );
// use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain)
//vp->setMaterialScheme("Fallback");
rtt->addListener(this);
rtt->setActive(true);
mReflectionTarget = rtt;
}
mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT";
createMaterial();
mWater->setMaterial(mMaterial);
mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water");
// ----------------------------------------------------------------------------------------------
// ---------------------------------- reflection debug overlay ----------------------------------
// ----------------------------------------------------------------------------------------------
/*
if (Settings::Manager::getBool("shader", "Water"))
{
OverlayManager& mgr = OverlayManager::getSingleton();
Overlay* overlay;
// destroy if already exists
if (overlay = mgr.getByName("ReflectionDebugOverlay"))
mgr.destroy(overlay);
overlay = mgr.create("ReflectionDebugOverlay");
if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture"))
MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture");
MaterialPtr debugMat = MaterialManager::getSingleton().create(
"Ogre/ReflectionDebugTexture",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName());
t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
OverlayContainer* debugPanel;
// destroy container if exists
try
{
if (debugPanel =
static_cast<OverlayContainer*>(
mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel"
)))
mgr.destroyOverlayElement(debugPanel);
}
catch (Ogre::Exception&) {}
debugPanel = (OverlayContainer*)
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel"));
debugPanel->_setPosition(0, 0.55);
debugPanel->_setDimensions(0.3, 0.3);
debugPanel->setMaterialName(debugMat->getName());
debugPanel->show();
overlay->add2D(debugPanel);
overlay->show();
}
*/
} }
void Water::setActive(bool active)
{
mActive = active;
updateVisible();
}
Water::~Water() Water::~Water()
{ {
Ogre::MeshManager::getSingleton().remove("water"); MeshManager::getSingleton().remove("water");
mWaterNode->detachObject(mWater); mWaterNode->detachObject(mWater);
mSceneManager->destroyEntity(mWater); mSceneManager->destroyEntity(mWater);
mSceneManager->destroySceneNode(mWaterNode); mSceneManager->destroySceneNode(mWaterNode);
Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); CompositorManager::getSingleton().removeCompositorChain(mViewport);
} }
void Water::changeCell(const ESM::Cell* cell) void Water::changeCell(const ESM::Cell* cell)
@ -65,31 +166,128 @@ void Water::setHeight(const float height)
void Water::toggle() void Water::toggle()
{ {
mWater->setVisible(!mWater->getVisible()); mToggled = !mToggled;
updateVisible();
} }
void Water::checkUnderwater(float y) void Water::checkUnderwater(float y)
{ {
if ((mIsUnderwater && y > mTop) || !mWater->isVisible()) if (!mActive) return;
if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID)
{ {
try { CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false);
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false);
} catch(...) {} // tell the shader we are not underwater
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0));
mWater->setRenderQueueGroup(RQG_Water);
mIsUnderwater = false; mIsUnderwater = false;
} }
if (!mIsUnderwater && y < mTop && mWater->isVisible()) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID)
{ {
try { if (mUnderwaterEffect)
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", true); CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true);
} catch(...) {}
// tell the shader we are underwater
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1));
mWater->setRenderQueueGroup(RQG_UnderWater);
mIsUnderwater = true; mIsUnderwater = true;
} }
updateVisible();
}
Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
{
return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2));
}
void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
{
if (evt.source == mReflectionTarget)
{
mReflectionCamera->setOrientation(mCamera->getDerivedOrientation());
mReflectionCamera->setPosition(mCamera->getDerivedPosition());
mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance());
mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance());
mReflectionCamera->setAspectRatio(mCamera->getAspectRatio());
mReflectionCamera->setFOVy(mCamera->getFOVy());
// Some messy code to get the skybox to show up at all
// The problem here is that it gets clipped by the water plane
// Therefore scale it up a bit
Vector3 pos = mCamera->getRealPosition();
pos.y = mTop*2 - pos.y;
mSky->setSkyPosition(pos);
mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f);
mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop));
mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop));
}
}
void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
{
if (evt.source == mReflectionTarget)
{
mSky->resetSkyPosition();
mSky->scaleSky(1);
mReflectionCamera->disableCustomNearClipPlane();
mReflectionCamera->disableReflection();
}
}
void Water::createMaterial()
{
mMaterial = MaterialManager::getSingleton().getByName("Water");
// these have to be set in code
std::string textureNames[32];
for (int i=0; i<32; ++i)
{
textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds";
}
mMaterial->getTechnique(1)->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2);
// use technique without shaders if reflection is disabled
if (mReflectionTarget == 0)
mMaterial->removeTechnique(0);
if (Settings::Manager::getBool("shader", "Water"))
{
CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mViewport)->getCompositor("gbuffer");
TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0);
TextureUnitState* tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap");
if (tus != 0)
tus->setTexture(colorTexture);
TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1);
tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap");
if (tus != 0)
tus->setTexture(depthTexture);
}
}
void Water::setViewportBackground(const ColourValue& bg)
{
if (mReflectionTarget)
mReflectionTarget->getViewport(0)->setBackgroundColour(bg);
} }
Ogre::Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) void Water::updateVisible()
{ {
return Ogre::Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); mWater->setVisible(mToggled && mActive);
if (mReflectionTarget)
mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater);
} }
} // namespace } // namespace

@ -4,10 +4,14 @@
#include <Ogre.h> #include <Ogre.h>
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
#include "renderconst.hpp"
namespace MWRender { namespace MWRender {
class SkyManager;
/// Water rendering /// Water rendering
class Water : Ogre::RenderTargetListener, Ogre::Camera::Listener class Water : public Ogre::RenderTargetListener
{ {
static const int CELL_SIZE = 8192; static const int CELL_SIZE = 8192;
Ogre::Camera *mCamera; Ogre::Camera *mCamera;
@ -19,16 +23,41 @@ namespace MWRender {
Ogre::Entity *mWater; Ogre::Entity *mWater;
bool mIsUnderwater; bool mIsUnderwater;
bool mActive;
bool mToggled;
int mTop; int mTop;
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
protected:
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void updateVisible();
SkyManager* mSky;
std::string mCompositorName;
void createMaterial();
Ogre::MaterialPtr mMaterial;
Ogre::Camera* mReflectionCamera;
Ogre::RenderTarget* mReflectionTarget;
bool mUnderwaterEffect;
int mVisibilityFlags;
public: public:
Water (Ogre::Camera *camera, const ESM::Cell* cell); Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell);
~Water(); ~Water();
void setActive(bool active);
void toggle(); void toggle();
void setViewportBackground(const Ogre::ColourValue& bg);
void checkUnderwater(float y); void checkUnderwater(float y);
void changeCell(const ESM::Cell* cell); void changeCell(const ESM::Cell* cell);
void setHeight(const float height); void setHeight(const float height);

@ -129,4 +129,10 @@ 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
opcodes 0x200014d-0x3ffffff unused

@ -280,6 +280,65 @@ 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);
}
};
const int numberOfAttributes = 8; const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027; const int opcodeGetAttribute = 0x2000027;
@ -311,6 +370,13 @@ 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;
void registerExtensions (Compiler::Extensions& extensions) void registerExtensions (Compiler::Extensions& extensions)
{ {
static const char *attributes[numberOfAttributes] = static const char *attributes[numberOfAttributes] =
@ -381,6 +447,11 @@ 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);
} }
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
@ -436,6 +507,14 @@ 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>);
} }
} }
} }

@ -26,7 +26,9 @@ namespace MWWorld
{ {
} }
void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const{
void Class::insertObject(const Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
{
} }

@ -10,7 +10,7 @@ namespace MWMechanics
namespace MWWorld namespace MWWorld
{ {
struct Environment; class Environment;
///< \brief Variant of the ContainerStore for NPCs ///< \brief Variant of the ContainerStore for NPCs
class InventoryStore : public ContainerStore class InventoryStore : public ContainerStore

@ -4,6 +4,7 @@
#include "../mwrender/player.hpp" #include "../mwrender/player.hpp"
#include "../mwmechanics/movement.hpp" #include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "world.hpp" #include "world.hpp"
#include "class.hpp" #include "class.hpp"
@ -48,6 +49,12 @@ namespace MWWorld
mClass = new_class; mClass = new_class;
} }
void Player::setDrawState(const DrawState& value)
{
MWWorld::Ptr ptr = getPlayer();
MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState = value;
}
void Player::setAutoMove (bool enable) void Player::setAutoMove (bool enable)
{ {
MWWorld::Ptr ptr = getPlayer(); MWWorld::Ptr ptr = getPlayer();
@ -97,5 +104,10 @@ namespace MWWorld
MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running);
} }
DrawState Player::getDrawState()
{
MWWorld::Ptr ptr = getPlayer();
return MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState;
}
} }

@ -8,6 +8,8 @@
#include "../mwworld/refdata.hpp" #include "../mwworld/refdata.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwmechanics/drawstate.hpp"
namespace MWRender namespace MWRender
{ {
class Player; class Player;
@ -18,7 +20,7 @@ namespace MWWorld
class World; class World;
/// \brief NPC object representing the player and additional player data /// \brief NPC object representing the player and additional player data
class Player class Player
{ {
ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> mPlayer; ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> mPlayer;
MWWorld::Ptr::CellStore *mCellStore; MWWorld::Ptr::CellStore *mCellStore;
@ -31,7 +33,6 @@ namespace MWWorld
ESM::Class *mClass; ESM::Class *mClass;
bool mAutoMove; bool mAutoMove;
int mForwardBackward; int mForwardBackward;
public: public:
Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world);
@ -76,6 +77,8 @@ namespace MWWorld
void setClass (const ESM::Class& class_); void setClass (const ESM::Class& class_);
void setDrawState(const DrawState& state);
std::string getName() const std::string getName() const
{ {
return mName; return mName;
@ -106,6 +109,8 @@ namespace MWWorld
return mAutoMove; return mAutoMove;
} }
DrawState getDrawState();
void setAutoMove (bool enable); void setAutoMove (bool enable);
void setLeftRight (int value); void setLeftRight (int value);

@ -221,7 +221,6 @@ namespace MWWorld
mWorld->adjustSky(); mWorld->adjustSky();
mCellChanged = true; mCellChanged = true;
mRendering.waterAdded(mCurrentCell);
} }
//We need the ogre renderer and a scene node. //We need the ogre renderer and a scene node.
@ -274,8 +273,6 @@ namespace MWWorld
mWorld->adjustSky(); mWorld->adjustSky();
mCellChanged = true; mCellChanged = true;
mRendering.waterAdded(cell);
} }
void Scene::changeToExteriorCell (const ESM::Position& position) void Scene::changeToExteriorCell (const ESM::Position& position)

@ -331,14 +331,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering, MWWorld::E
void WeatherManager::setWeather(const String& weather, bool instant) void WeatherManager::setWeather(const String& weather, bool instant)
{ {
if (weather == mCurrentWeather && mNextWeather == "") if (weather == mCurrentWeather && mNextWeather == "")
{
mFirstUpdate = false;
return; return;
}
if (instant || mFirstUpdate) if (instant || mFirstUpdate)
{ {
mNextWeather = ""; mNextWeather = "";
mCurrentWeather = weather; mCurrentWeather = weather;
mFirstUpdate = false;
} }
else else
{ {
@ -352,6 +354,7 @@ void WeatherManager::setWeather(const String& weather, bool instant)
mNextWeather = weather; mNextWeather = weather;
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600; mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta*24.f*3600;
} }
mFirstUpdate = false;
} }
WeatherResult WeatherManager::getResult(const String& weather) WeatherResult WeatherManager::getResult(const String& weather)
@ -469,6 +472,7 @@ WeatherResult WeatherManager::transition(float factor)
result.mCloudSpeed = current.mCloudSpeed; result.mCloudSpeed = current.mCloudSpeed;
result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity);
result.mGlareView = lerp(current.mGlareView, other.mGlareView); result.mGlareView = lerp(current.mGlareView, other.mGlareView);
result.mNightFade = lerp(current.mNightFade, other.mNightFade);
result.mNight = current.mNight; result.mNight = current.mNight;
@ -517,23 +521,23 @@ void WeatherManager::update(float duration)
srand(time(NULL)); srand(time(NULL));
float random = ((rand()%100)/100.f) * total; float random = ((rand()%100)/100.f) * total;
//if (random > snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
// weather = "blizzard"; // weather = "blizzard";
//else if (random > blight+ash+thunder+rain+overcast+foggy+cloudy+clear) //else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear)
// weather = "snow"; // weather = "snow";
/*else*/ if (random > ash+thunder+rain+overcast+foggy+cloudy+clear) /*else*/ if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear)
weather = "blight"; weather = "blight";
else if (random > thunder+rain+overcast+foggy+cloudy+clear) else if (random >= thunder+rain+overcast+foggy+cloudy+clear)
weather = "ashstorm"; weather = "ashstorm";
else if (random > rain+overcast+foggy+cloudy+clear) else if (random >= rain+overcast+foggy+cloudy+clear)
weather = "thunderstorm"; weather = "thunderstorm";
else if (random > overcast+foggy+cloudy+clear) else if (random >= overcast+foggy+cloudy+clear)
weather = "rain"; weather = "rain";
else if (random > foggy+cloudy+clear) else if (random >= foggy+cloudy+clear)
weather = "overcast"; weather = "overcast";
else if (random > cloudy+clear) else if (random >= cloudy+clear)
weather = "foggy"; weather = "foggy";
else if (random > clear) else if (random >= clear)
weather = "cloudy"; weather = "cloudy";
else else
weather = "clear"; weather = "clear";
@ -581,8 +585,8 @@ void WeatherManager::update(float duration)
int facing = (mHour > 13.f) ? 1 : -1; int facing = (mHour > 13.f) ? 1 : -1;
Vector3 final( Vector3 final(
(1-height)*facing, -(1-height)*facing,
(1-height)*facing, -(1-height)*facing,
height); height);
mRendering->setSunDirection(final); mRendering->setSunDirection(final);

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

@ -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;
@ -282,15 +283,61 @@ void NIFLoader::createMaterial(const String &name,
// other values. 237 basically means normal transparencly. // other values. 237 basically means normal transparencly.
if (alphaFlags == 237) if (alphaFlags == 237)
{ {
// Enable transparency NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName);
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); if (result.first)
{
pass->setAlphaRejectFunction(CMPF_GREATER_EQUAL);
pass->setAlphaRejectValue(result.second);
}
else
{
// Enable transparency
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,137 +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"))
{
// 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 oFogValue : TEXCOORD3, \n"
" out float4 oVertexColour : TEXCOORD4, \n"
" uniform float4 fogParams, \n"
" uniform float4x4 worldViewProj \n"
") \n"
"{ \n"
" oVertexColour = colour; \n"
" oUV = uv; \n"
" oNormal = normal; \n"
" oPosition = mul( worldViewProj, position ); \n"
" oFogValue = saturate((oPosition.z - fogParams.y) * fogParams.w); \n"
" oPositionObjSpace = position; \n"
"}";
vertex->setSource(outStream.str());
vertex->load();
vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);
vertex->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS);
}
else
vertex = mgr.getByName("main_vp");
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 fogValue : TEXCOORD3, \n"
" float4 vertexColour : TEXCOORD4, \n"
" uniform float4 fogColour, \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"
" oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour, fogValue); \n"
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n"
"}";
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);
}
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

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

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

@ -1,13 +1,16 @@
project(resources) project(resources)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_Fresnel.cg "${OpenMW_BINARY_DIR}/resources/water/Example_Fresnel.cg" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/underwater.cg "${OpenMW_BINARY_DIR}/resources/water/underwater.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Example_FresnelPS.asm "${OpenMW_BINARY_DIR}/resources/water/Example_FresnelPS.asm" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassFP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassFP.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/GlassVP.cg "${OpenMW_BINARY_DIR}/resources/water/GlassVP.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Water02.jpg "${OpenMW_BINARY_DIR}/resources/water/Water02.jpg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/waves2.dds "${OpenMW_BINARY_DIR}/resources/water/waves2.dds" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/Examples-Water.material "${OpenMW_BINARY_DIR}/resources/water/Examples-Water.material" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal2.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal2.tga" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal1.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal1.tga" COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/resources/water/water.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY)
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)

@ -0,0 +1,18 @@
void RenderScene_vs(in float4 position : POSITION
,in float2 uv :TEXCOORD0
,uniform float4x4 wvp
,out float4 oPosition : POSITION
,out float2 oUV :TEXCOORD0)
{
oPosition = mul(wvp, position);
oUV = uv;
}
void RenderScene_ps(in float4 position : POSITION
,in float2 uv :TEXCOORD0
,uniform sampler2D tex1 : TEXUNIT0
,out float4 oColor : COLOR)
{
float4 scene =tex2D(tex1, uv);
oColor= scene;
}

@ -0,0 +1,95 @@
// Compositor that just controls output to the MRT textures
compositor gbuffer
{
technique
{
// MRT output. Currently this is a color texture plus a depth texture
texture mrt_output target_width target_height PF_FLOAT16_RGBA PF_FLOAT16_RGBA chain_scope depth_pool 2
target mrt_output
{
input none
pass clear
{
clear
{
// make sure to set this to the viewport background color from outside
colour_value 0 0 0 1
}
}
pass render_scene
{
// Renders everything except water
first_render_queue 0
last_render_queue 70
}
}
target_output
{
input none
pass render_quad
{
material RenderScene
input 0 mrt_output 0
}
}
}
}
// Finalizer compositor to render objects that we don't want in the MRT textures (ex. water)
// NB the water has to be rendered in a seperate compositor anyway, because it
// accesses the MRT textures which can't be done while they are still being rendered to.
compositor gbufferFinalizer
{
technique
{
texture no_mrt_output target_width target_height PF_R8G8B8A8 depth_pool 2 no_fsaa
texture previousscene target_width target_height PF_R8G8B8A8
target previousscene
{
input previous
}
target no_mrt_output
{
input none
shadows off
pass clear
{
clear
{
buffers colour
colour_value 0 0 0 0
}
}
pass render_quad
{
material RenderSceneNoDepth
input 0 previousscene
}
pass render_scene
{
first_render_queue 71
last_render_queue 100
}
}
target_output
{
input none
pass clear
{
clear
{
}
}
pass render_quad
{
material RenderSceneNoDepth
input 0 no_mrt_output
}
}
}
}

@ -0,0 +1,63 @@
vertex_program RenderGBuffer_vs cg
{
source gbuffer.cg
profiles vs_4_0 vs_1_1 arbvp1
entry_point RenderScene_vs
default_params
{
param_named_auto wvp worldviewproj_matrix
}
}
fragment_program RenderGBuffer_ps cg
{
source gbuffer.cg
entry_point RenderScene_ps
profiles ps_4_0 ps_2_x arbfp1
default_params
{
}
}
material RenderScene
{
technique
{
pass
{
vertex_program_ref RenderGBuffer_vs
{
}
fragment_program_ref RenderGBuffer_ps
{
}
texture_unit tex1
{
//scenebuffer
}
}
}
}
material RenderSceneNoDepth
{
technique
{
pass
{
depth_write off
vertex_program_ref RenderGBuffer_vs
{
}
fragment_program_ref RenderGBuffer_ps
{
}
texture_unit tex1
{
//scenebuffer
}
}
}
}

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

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

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

@ -1,8 +1,12 @@
# WARNING: Editing this file might have no effect, as these
# settings are overwritten by your user settings file.
[General] [General]
# Camera field of view # Camera field of view
field of view = 55 field of view = 55
# Texture filtering mode. valid values: # Texture filtering mode. valid values:
# none
# anisotropic # anisotropic
# bilinear # bilinear
# trilinear # trilinear
@ -14,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
@ -54,6 +84,21 @@ fog end factor = 1.0
# Max. number of lights that affect the terrain. Setting to 1 will only reflect sunlight # Max. number of lights that affect the terrain. Setting to 1 will only reflect sunlight
num lights = 8 num lights = 8
[Water]
# Enable this to get fancy-looking water with reflections and refractions
# All the settings below have no effect if this is false
shader = true
rtt size = 512
reflect terrain = true
reflect statics = false
reflect small statics = false
reflect actors = true
reflect misc = false
# Enable underwater effect. It is not resource intensive, so only disable it if you have problems.
underwater effect = true
[Sound] [Sound]
# Device name. Blank means default # Device name. Blank means default
device = device =

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

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

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

@ -1,116 +0,0 @@
// Vertex program for fresnel reflections / refractions
void main_vp(
float4 pos : POSITION,
float4 normal : NORMAL,
float2 tex : TEXCOORD0,
out float4 oPos : POSITION,
out float3 noiseCoord : TEXCOORD0,
out float4 projectionCoord : TEXCOORD1,
out float3 oEyeDir : TEXCOORD2,
out float3 oNormal : TEXCOORD3,
uniform float4x4 worldViewProjMatrix,
uniform float3 eyePosition, // object space
uniform float timeVal,
uniform float scale, // the amount to scale the noise texture by
uniform float scroll, // the amount by which to scroll the noise
uniform float noise // the noise perturb as a factor of the time
)
{
oPos = mul(worldViewProjMatrix, pos);
// Projective texture coordinates, adjust for mapping
float4x4 scalemat = float4x4(0.5, 0, 0, 0.5,
0,-0.5, 0, 0.5,
0, 0, 0.5, 0.5,
0, 0, 0, 1);
projectionCoord = mul(scalemat, oPos);
// Noise map coords
noiseCoord.xy = (tex + (timeVal * scroll)) * scale;
noiseCoord.z = noise * timeVal;
oEyeDir = normalize(pos.xyz - eyePosition);
oNormal = normal.rgb;
}
// Fragment program for distorting a texture using a 3D noise texture
void main_fp(
float3 noiseCoord : TEXCOORD0,
float4 projectionCoord : TEXCOORD1,
float3 eyeDir : TEXCOORD2,
float3 normal : TEXCOORD3,
out float4 col : COLOR,
uniform float4 tintColour,
uniform float noiseScale,
uniform float fresnelBias,
uniform float fresnelScale,
uniform float fresnelPower,
uniform sampler2D waterTex : register(s0),
uniform sampler2D noiseMap : register(s1),
uniform sampler2D reflectMap : register(s2),
uniform sampler2D refractMap : register(s3)
)
{
// Do the tex projection manually so we can distort _after_
float2 final = projectionCoord.xy / projectionCoord.w;
// Noise
float3 noiseNormal = (tex2D(noiseMap, (noiseCoord.xy / 5)).rgb - 0.5).rbg * noiseScale;
final += noiseNormal.xz;
// Fresnel
//normal = normalize(normal + noiseNormal.xz);
float fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower);
// Reflection / refraction
float4 reflectionColour = tex2D(reflectMap, final);
float4 refractionColour = tex2D(refractMap, final) + tintColour;
// Final colour
col = lerp(refractionColour, reflectionColour, fresnel) * tex2D(waterTex, noiseNormal) / 3 ;
}
// Old version to match ATI PS 1.3 implementation
void main_vp_old(
float4 pos : POSITION,
float4 normal : NORMAL,
float2 tex : TEXCOORD0,
out float4 oPos : POSITION,
out float fresnel : COLOR,
out float3 noiseCoord : TEXCOORD0,
out float4 projectionCoord : TEXCOORD1,
uniform float4x4 worldViewProjMatrix,
uniform float3 eyePosition, // object space
uniform float fresnelBias,
uniform float fresnelScale,
uniform float fresnelPower,
uniform float timeVal,
uniform float scale, // the amount to scale the noise texture by
uniform float scroll, // the amount by which to scroll the noise
uniform float noise // the noise perturb as a factor of the time
)
{
oPos = mul(worldViewProjMatrix, pos);
// Projective texture coordinates, adjust for mapping
float4x4 scalemat = float4x4(0.5, 0, 0, 0.5,
0,-0.5, 0, 0.5,
0, 0, 0.5, 0.5,
0, 0, 0, 1);
projectionCoord = mul(scalemat, oPos);
// Noise map coords
noiseCoord.xy = (tex + (timeVal * scroll)) * scale;
noiseCoord.z = noise * timeVal;
// calc fresnel factor (reflection coefficient)
float3 eyeDir = normalize(pos.xyz - eyePosition);
fresnel = fresnelBias + fresnelScale * pow(1 + dot(eyeDir, normal), fresnelPower);
}

@ -1,72 +0,0 @@
ps.1.4
// conversion from Cg generated ARB_fragment_program to ps.1.4 by NFZ
// command line args: -profile arbfp1 -entry main_fp
// program main_fp
// c0 : distortionRange
// c1 : tintColour
// testure 0 : noiseMap
// texture 1 : reflectMap
// texture 2 : refractMap
// v0.x : fresnel
// t0.xyz : noiseCoord
// t1.xyw : projectionCoord
def c2, 2, 1, 0, 0
// Cg: distort.x = tex3D(noiseMap, noiseCoord).x;
// arbfp1: TEX R0.x, fragment.texcoord[0], texture[0], 3D;
// sample noise map using noiseCoord in TEX unit 0
texld r0, t0.xyz
// get projected texture coordinates from TEX coord 1
// will be used in phase 2
texcrd r1.xy, t1_dw.xyw
mov r1.z, c2.y
// Cg: distort.y = tex3D(noiseMap, noiseCoord + yoffset).x;
// arbfp1: ADD R1.xyz, fragment.texcoord[0], c1;
// arbfp1: TEX R1.x, R1, texture[0], 3D;
// arbfp1: MOV R0.y, R1.x;
// Cg: distort = (distort * 2 - 1) * distortionRange;
// arbfp1: MAD R0.xy, R0, c0.x, -c0.y;
// arbfp1: MUL R0.xy, R0, u0.x;
// (distort * 2 - 1) same as 2*(distort -.5) so use _bx2
// Cg: final = projectionCoord.xy / projectionCoord.w;
// Cg: final += distort;
// arbfp1: RCP R0.w, fragment.texcoord[1].w;
// arbfp1: MAD R0.xy, fragment.texcoord[1], R0.w, R0;
// final = (distort * projectionCoord.w) + projectionCoord.xy
// for ps.1.4 have to re-arrange things a bit to perturb projected texture coordinates
mad r0.xyz, r0_bx2, c0.x, r1
phase
// do dependant texture reads
// Cg: reflectionColour = tex2D(reflectMap, final);
// arbfp1: TEX R0, R0, texture[1], 2D;
// sampe reflectMap using dependant read : texunit 1
texld r1, r0.xyz
// Cg: refractionColour = tex2D(refractMap, final) + tintColour;
// arbfp1: TEX R1, R0, texture[2], 2D;
// sample refractMap : texunit 2
texld r2, r0.xyz
// adding tintColour that is in global c1
// arbfp1: ADD R1, R1, u1;
add r2, r2, c1
// Cg: col = lerp(refractionColour, reflectionColour, fresnel);
// arbfp1: ADD R0, R0, -R1;
// arbfp1: MAD result.color, fragment.color.primary.x, R0, R1;
lrp r0, v0.x, r1, r2

@ -1,149 +0,0 @@
vertex_program Water/GlassVP cg
{
source GlassVP.cg
entry_point glass_vp
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}
fragment_program Water/GlassFP cg
{
source GlassFP.cg
entry_point main_ps
profiles ps_2_0 arbfp1
}
material Water/Compositor
{
technique
{
pass
{
depth_check off
vertex_program_ref Water/GlassVP
{
param_named_auto timeVal time 0.25
param_named scale float 0.1
}
fragment_program_ref Water/GlassFP
{
param_named tintColour float4 0 0.35 0.35 1
}
texture_unit RT
{
tex_coord_set 0
tex_address_mode clamp
filtering linear linear linear
}
texture_unit
{
texture WaterNormal1.tga 2d
tex_coord_set 1
//tex_address_mode clamp
filtering linear linear linear
}
texture_unit
{
texture caustic_0.png 2d
tex_coord_set 2
//tex_address_mode clamp
filtering linear linear linear
}
}
}
}
vertex_program Water/RefractReflectVP cg
{
source Example_Fresnel.cg
entry_point main_vp
profiles vs_1_1 arbvp1
}
vertex_program Water/RefractReflectVPold cg
{
source Example_Fresnel.cg
entry_point main_vp_old
profiles vs_1_1 arbvp1
}
fragment_program Water/RefractReflectFP cg
{
source Example_Fresnel.cg
entry_point main_fp
// sorry, ps_1_1 and fp20 can't do this
profiles ps_2_0 arbfp1
}
fragment_program Water/RefractReflectPS asm
{
source Example_FresnelPS.asm
// sorry, only for ps_1_4 :)
syntax ps_1_4
}
material Examples/Water0
{
technique
{
pass
{
//
depth_write off
vertex_program_ref Water/RefractReflectVP
{
param_named_auto worldViewProjMatrix worldviewproj_matrix
param_named_auto eyePosition camera_position_object_space
param_named_auto timeVal time 0.15
param_named scroll float 1
param_named scale float 1
param_named noise float 1
// scroll and noisePos will need updating per frame
}
fragment_program_ref Water/RefractReflectFP
{
param_named fresnelBias float -0.1
param_named fresnelScale float 0.8
param_named fresnelPower float 20
param_named tintColour float4 1 1 1 1
param_named noiseScale float 0.05
}
// Water
scene_blend alpha_blend
texture_unit
{
// Water texture
texture Water02.jpg
// min / mag filtering, no mip
filtering linear linear none
alpha_op_ex source1 src_manual src_current 0.9
}
// Noise
texture_unit
{
alpha_op_ex source1 src_manual src_current 0.9
// Perlin noise volume
texture waves2.dds
// min / mag filtering, no mip
filtering linear linear none
}
}
}
}

@ -1,15 +0,0 @@
sampler RT : register(s0);
sampler NormalMap : register(s1);
sampler CausticMap : register(s2);
float4 main_ps(float2 iTexCoord : TEXCOORD0,
float3 noiseCoord : TEXCOORD1,
uniform float4 tintColour) : COLOR
{
float4 normal = tex2D(NormalMap, noiseCoord);
return tex2D(RT, iTexCoord + normal.xy * 0.05) +
(tex2D(CausticMap, noiseCoord) / 5) +
tintColour ;
}

@ -1,24 +0,0 @@
void glass_vp
(
in float4 inPos : POSITION,
out float4 pos : POSITION,
out float2 uv0 : TEXCOORD0,
out float4 noiseCoord : TEXCOORD1,
uniform float4x4 worldViewProj,
uniform float timeVal,
uniform float scale
)
{
// Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc)
pos = mul(worldViewProj, inPos);
// The input positions adjusted by texel offsets, so clean up inaccuracies
inPos.xy = sign(inPos.xy);
// Convert to image-space
uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f;
noiseCoord = (pos + timeVal) * scale;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

@ -0,0 +1,61 @@
void main_vp
(
in float4 inPos : POSITION,
out float4 pos : POSITION,
out float2 uv0 : TEXCOORD0,
out float4 noiseCoord : TEXCOORD1,
uniform float4x4 worldViewProj,
uniform float timeVal,
uniform float scale
)
{
// Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc)
pos = mul(worldViewProj, inPos);
// The input positions adjusted by texel offsets, so clean up inaccuracies
inPos.xy = sign(inPos.xy);
// Convert to image-space
uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f;
noiseCoord = (pos + timeVal) * scale;
}
float4 main_fp_nomrt (float2 iTexCoord : TEXCOORD0,
float3 noiseCoord : TEXCOORD1,
uniform sampler2D RT : register(s0),
uniform sampler2D NormalMap : register(s1),
uniform sampler2D CausticMap : register(s2),
uniform float4 tintColour) : COLOR
{
float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1;
return tex2D(RT, iTexCoord + normal.xy * 0.015) +
(tex2D(CausticMap, noiseCoord) / 5) +
tintColour ;
}
float4 main_fp (float2 iTexCoord : TEXCOORD0,
float3 noiseCoord : TEXCOORD1,
uniform float far,
uniform sampler2D RT : register(s0),
uniform sampler2D NormalMap : register(s1),
uniform sampler2D CausticMap : register(s2),
uniform sampler2D DepthMap : register(s3),
uniform float4 tintColour) : COLOR
{
float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1;
float depth = tex2D(DepthMap, iTexCoord + normal.xy * 0.015).r * far;
depth = saturate(depth / 2000.f);
float4 color = tex2D(RT, iTexCoord + normal.xy * 0.015) +
(tex2D(CausticMap, noiseCoord) / 5) +
tintColour;
return lerp(color, float4(0, 0.65, 0.65, 1), depth);
}

@ -0,0 +1,121 @@
void main_vp
(
in float4 iPos : POSITION
, in float2 iUv : TEXCOORD0
, out float4 oPos : POSITION
, out float3 oScreenCoords : TEXCOORD0
, out float2 oUv : TEXCOORD1
, out float oDepth : TEXCOORD2
, out float4 oEyeVector : TEXCOORD3
, uniform float4x4 wvpMat
, uniform float4 camPosObjSpace
)
{
oPos = mul(wvpMat, iPos);
oUv = iUv * 10; // uv scale
oDepth = oPos.z;
float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5,
0, -0.5, 0, 0.5,
0, 0, 0.5, 0.5,
0, 0, 0, 1 );
float4 texcoordProj = mul(scalemat, oPos);
oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w);
oEyeVector = camPosObjSpace - iPos;
}
void main_fp
(
out float4 oColor : COLOR
, in float3 iScreenCoords : TEXCOORD0
, in float2 iUv : TEXCOORD1
, in float iDepth : TEXCOORD2
, in float4 iEyeVector : TEXCOORD3
, uniform float renderTargetFlipping
, uniform float4 lightPosObjSpace0
, uniform float4 lightSpecularColour0
, uniform sampler2D reflectionMap : register(s0)
, uniform sampler2D refractionMap : register(s1)
, uniform sampler2D depthMap : register(s2)
, uniform sampler2D normalMap : register(s3)
, uniform float time
, uniform float far
, uniform float4 fogParams
, uniform float4 fogColour
, uniform float isUnderwater
)
{
float2 screenCoords = iScreenCoords.xy / iScreenCoords.z;
screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y;
// No need for transparency since we are using a refraction map
oColor.a = 1;
// Sample screen-space depth map and subtract pixel depth to get the real water depth
float depthTex = tex2D(depthMap, screenCoords).r;
float depth1 = depthTex * far - iDepth;
depth1 = saturate(depth1 / 500.f);
// Simple wave effect. to be replaced by something better
float2 uv1 = iUv + time * float2(0.5, 0);
float2 uv2 = iUv + time * float2(0, 0.5);
float2 uv3 = iUv + time * float2(-0.5, 0);
float2 uv4 = iUv + time * float2(0, -0.5);
float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4);
normal = normal / 4.f;
normal = 2*normal - 1;
float2 screenCoords_reflect = screenCoords + normal.yx * 0.05;
float2 screenCoords_refract = screenCoords + normal.yx * 0.05 * depth1;
// Sample depth again with the refracted coordinates
depthTex = tex2D(depthMap, screenCoords_refract).r;
float depth2 = (depthTex * far - iDepth) / 500.f;
depth2 = (depthTex == 0 ? 1 : depth2);
// if depth2 is less than 0, this means we would refract something which is above water,
// which we don't want to - so in that case, don't refract
if (depth2 < 0.25) // delta due to inaccuracies
{
screenCoords_refract = screenCoords;
depth2 = depth1;
}
depth2 = saturate(depth2);
float4 reflection = tex2D(reflectionMap, screenCoords_reflect);
float4 refraction = tex2D(refractionMap, screenCoords_refract);
// tangent to object space
normal.xyz = normal.xzy;
iEyeVector.xyz = normalize(iEyeVector.xyz);
// fresnel
float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0);
float reflectionFactor = saturate(0.35 + 0.65 * pow(facing, 2));
// specular
float3 lightDir = normalize(lightPosObjSpace0.xyz); // assumes that light 0 is a directional light
float3 halfVector = normalize(iEyeVector + lightDir);
float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64);
float opacity = depth2 * saturate(reflectionFactor + specular);
opacity *= (1-isUnderwater);
reflection.xyz += lightSpecularColour0.xyz * specular;
oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity);
oColor.xyz += isUnderwater * float3(0, 0.35, 0.35); // underwater tint color
oColor.xyz = lerp(oColor.xyz, float3(0, 0.65, 0.65), saturate(isUnderwater * (iDepth / 2000.f))); // underwater fog
// add fog
//float fogValue = saturate((iDepth - fogParams.y) * fogParams.w);
//oColor.xyz = lerp(oColor.xyz, fogColour, fogValue);
}

@ -1,4 +1,4 @@
compositor Water compositor UnderwaterNoMRT
{ {
technique technique
{ {
@ -6,6 +6,30 @@ compositor Water
target rt0 { input previous } target rt0 { input previous }
target_output
{
// Start with clear output
input none
pass render_quad
{
material Water/CompositorNoMRT
input 0 rt0
}
}
}
}
compositor Underwater
{
technique
{
texture_ref scene gbuffer mrt_output
texture rt0 target_width target_height PF_R8G8B8
target rt0 { input previous }
target_output target_output
{ {
// Start with clear output // Start with clear output
@ -15,7 +39,8 @@ compositor Water
{ {
material Water/Compositor material Water/Compositor
input 0 rt0 input 0 rt0
input 3 scene 1
} }
} }
} }
} }

@ -0,0 +1,198 @@
vertex_program UnderwaterEffectVP cg
{
source underwater.cg
entry_point main_vp
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}
fragment_program UnderwaterEffectFP_NoMRT cg
{
source underwater.cg
entry_point main_fp_nomrt
profiles ps_2_0 arbfp1
}
fragment_program UnderwaterEffectFP cg
{
source underwater.cg
entry_point main_fp
profiles ps_2_0 arbfp1
}
vertex_program Water_VP cg
{
source water.cg
entry_point main_vp
profiles vs_2_x arbvp1
default_params
{
param_named_auto wvpMat worldviewproj_matrix
}
}
fragment_program Water_FP cg
{
source water.cg
entry_point main_fp
profiles ps_2_x arbfp1
}
material Water
{
technique
{
pass
{
cull_hardware none
vertex_program_ref Water_VP
{
param_named_auto camPosObjSpace camera_position_object_space
}
fragment_program_ref Water_FP
{
param_named_auto time time 0.1
//param_named_auto fogColour fog_colour
//param_named_auto fogParams fog_params
param_named_auto renderTargetFlipping render_target_flipping
param_named_auto far far_clip_distance
param_named_auto lightPosObjSpace0 light_position_object_space 0
param_named_auto lightSpecularColour0 light_specular_colour 0
param_named isUnderwater float 0
}
texture_unit reflectionMap
{
texture WaterReflection
tex_address_mode clamp
}
texture_unit refractionMap
{
tex_address_mode clamp
}
texture_unit depthMap
{
tex_address_mode clamp
}
texture_unit normalMap
{
texture WaterNormal2.tga
}
}
}
technique
{
scheme Fallback
pass
{
cull_hardware none
scene_blend alpha_blend
depth_write off
diffuse 0 0 0 1
emissive 0.6 0.7 1.0
ambient 0 0 0
texture_unit
{
// texture names set via code
scale 0.1 0.1
alpha_op_ex source1 src_manual src_current 0.7
}
}
}
}
material Water/CompositorNoMRT
{
technique
{
pass
{
depth_check off
vertex_program_ref UnderwaterEffectVP
{
param_named_auto timeVal time 0.25
param_named scale float 0.1
}
fragment_program_ref UnderwaterEffectFP_NoMRT
{
param_named tintColour float4 0 0.35 0.35 1
}
texture_unit RT
{
tex_coord_set 0
tex_address_mode clamp
filtering linear linear linear
}
texture_unit
{
texture WaterNormal2.tga 2d
tex_coord_set 1
//tex_address_mode clamp
filtering linear linear linear
}
texture_unit
{
texture caustic_0.png 2d
tex_coord_set 2
//tex_address_mode clamp
filtering linear linear linear
}
}
}
}
material Water/Compositor
{
technique
{
pass
{
depth_check off
vertex_program_ref UnderwaterEffectVP
{
param_named_auto timeVal time 0.25
param_named scale float 0.1
}
fragment_program_ref UnderwaterEffectFP
{
param_named tintColour float4 0 0.35 0.35 1
param_named_auto far far_clip_distance
}
texture_unit RT
{
tex_coord_set 0
tex_address_mode clamp
}
texture_unit
{
texture WaterNormal2.tga 2d
tex_coord_set 2
}
texture_unit
{
texture caustic_0.png 2d
tex_coord_set 3
}
texture_unit DepthMap
{
}
}
}
}

Binary file not shown.

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

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

@ -95,6 +95,7 @@ Allowed options:
CREDITS CREDITS
Current Developers: Current Developers:
Aleksandar Jovanov
Alexander “Ace” Olofsson Alexander “Ace” Olofsson
athile athile
BrotherBrick BrotherBrick

Loading…
Cancel
Save