diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 45ce1b9af..c08c91c02 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,6 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper + compositors ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/compositors.cpp b/apps/openmw/mwrender/compositors.cpp new file mode 100644 index 000000000..4c9f08b72 --- /dev/null +++ b/apps/openmw/mwrender/compositors.cpp @@ -0,0 +1,49 @@ +#include "compositors.hpp" + +#include +#include + +using namespace MWRender; + +Compositors::Compositors(Ogre::Viewport* vp) : + mViewport(vp) + , mEnabled(true) +{ +} + +Compositors::~Compositors() +{ + Ogre::CompositorManager::getSingleton().removeCompositorChain(mViewport); +} + +void Compositors::setEnabled (const bool enabled) +{ + for (CompositorMap::iterator it=mCompositors.begin(); + it != mCompositors.end(); ++it) + { + Ogre::CompositorManager::getSingleton().setCompositorEnabled(mViewport, it->first, enabled && it->second.first); + } + mEnabled = enabled; +} + +void Compositors::addCompositor (const std::string& name, const int priority) +{ + int id = 0; + + for (CompositorMap::iterator it=mCompositors.begin(); + it != mCompositors.end(); ++it) + { + if (it->second.second > priority) + break; + ++id; + } + Ogre::CompositorManager::getSingleton().addCompositor (mViewport, name, id); + + mCompositors[name] = std::make_pair(false, priority); +} + +void Compositors::setCompositorEnabled (const std::string& name, const bool enabled) +{ + mCompositors[name].first = enabled; + Ogre::CompositorManager::getSingleton().setCompositorEnabled (mViewport, name, enabled && mEnabled); +} diff --git a/apps/openmw/mwrender/compositors.hpp b/apps/openmw/mwrender/compositors.hpp new file mode 100644 index 000000000..50b53f84a --- /dev/null +++ b/apps/openmw/mwrender/compositors.hpp @@ -0,0 +1,53 @@ +#ifndef GAME_MWRENDER_COMPOSITORS_H +#define GAME_MWRENDER_COMPOSITORS_H + +#include +#include + +namespace Ogre +{ + class Viewport; +} + +namespace MWRender +{ + typedef std::map < std::string, std::pair > CompositorMap; + + /// \brief Manages a set of compositors for one viewport + class Compositors + { + public: + Compositors(Ogre::Viewport* vp); + virtual ~Compositors(); + + /** + * enable or disable all compositors globally + */ + void setEnabled (const bool enabled); + + bool toggle() { setEnabled(!mEnabled); return mEnabled; } + + /** + * enable or disable a specific compositor + * @note enable has no effect if all compositors are globally disabled + */ + void setCompositorEnabled (const std::string& name, const bool enabled); + + /** + * @param name of compositor + * @param priority, lower number will be first in the chain + */ + void addCompositor (const std::string& name, const int priority); + + protected: + /// maps compositor name to its "enabled" state + CompositorMap mCompositors; + + bool mEnabled; + + Ogre::Viewport* mViewport; + }; + +} + +#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d49a96101..6d0b1b21c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -19,6 +19,7 @@ #include "shaderhelper.hpp" #include "localmap.hpp" #include "water.hpp" +#include "compositors.hpp" using namespace MWRender; using namespace Ogre; @@ -30,6 +31,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const { mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); + mCompositors = new Compositors(mRendering.getViewport()); + mWater = 0; //The fog type must be set before any terrain objects are created as if the @@ -68,15 +71,15 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // 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); + mCompositors->addCompositor("gbuffer", 0); + mCompositors->setCompositorEnabled("gbuffer", true); + mCompositors->addCompositor("Underwater", 1); + mCompositors->addCompositor("gbufferFinalizer", 2); + mCompositors->setCompositorEnabled("gbufferFinalizer", true); } else { - CompositorManager::getSingleton().addCompositor(mRendering.getViewport(), "UnderwaterNoMRT"); + mCompositors->addCompositor("UnderwaterNoMRT", 0); } // Turn the entire scene (represented by the 'root' node) -90 @@ -121,6 +124,7 @@ RenderingManager::~RenderingManager () delete mTerrainManager; delete mLocalMap; delete mOcclusionQuery; + delete mCompositors; } MWRender::SkyManager* RenderingManager::getSkyManager() @@ -235,7 +239,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ && !MWBase::Environment::get().getWorld()->getStore().lands.search(store->cell->data.gridX,store->cell->data.gridY) )) // always use water, if the cell does not have land. { if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), mSkyManager, store->cell); + mWater = new MWRender::Water(mRendering.getCamera(), this, store->cell); else mWater->changeCell(store->cell); mWater->setActive(true); @@ -295,35 +299,29 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { - if (mode != MWWorld::World::Render_Wireframe) + if (mode == MWWorld::World::Render_CollisionDebug || mode == MWWorld::World::Render_Pathgrid) return mDebugging->toggleRenderMode(mode); - else // if (mode == MWWorld::World::Render_Wireframe) + else if (mode == MWWorld::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { - // disable compositors - if (useMRT()) - { - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", false); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", false); - } + mCompositors->setEnabled(false); mRendering.getCamera()->setPolygonMode(PM_WIREFRAME); return true; } else { - // re-enable compositors - if (useMRT()) - { - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbuffer", true); - CompositorManager::getSingleton().setCompositorEnabled(mRendering.getViewport(), "gbufferFinalizer", true); - } + mCompositors->setEnabled(true); mRendering.getCamera()->setPolygonMode(PM_SOLID); return false; } } + else //if (mode == MWWorld::World::Render_Compositors) + { + return mCompositors->toggle(); + } } void RenderingManager::configureFog(ESMS::CellStore &mCell) @@ -529,13 +527,13 @@ Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; - // expand the screen-space bounding-box so that it completely encloses + // expand the screen-space bounding-box so that it completely encloses // the object's AABB for (int i=0; i<8; i++) { Ogre::Vector3 corner = corners[i]; - // multiply the AABB corner vertex by the view matrix to + // multiply the AABB corner vertex by the view matrix to // get a camera-space vertex corner = mat * corner; @@ -544,20 +542,25 @@ Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) float x = corner.x / corner.z + 0.5; float y = corner.y / corner.z + 0.5; - if (x < min_x) + if (x < min_x) min_x = x; - if (x > max_x) + if (x > max_x) max_x = x; - if (y < min_y) + if (y < min_y) min_y = y; - if (y > max_y) + if (y > max_y) max_y = y; } return Vector4(min_x, min_y, max_x, max_y); } +Compositors* RenderingManager::getCompositors() +{ + return mCompositors; +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 8b457997d..5ef43a2e2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -47,6 +47,7 @@ namespace MWRender class ShaderHelper; class LocalMap; class Water; + class Compositors; class RenderingManager: private RenderingInterface { @@ -67,6 +68,7 @@ class RenderingManager: private RenderingInterface { /// to internal details of the rendering system anymore SkyManager* getSkyManager(); + Compositors* getCompositors(); void toggleLight(); bool toggleRenderMode(int mode); @@ -196,6 +198,8 @@ class RenderingManager: private RenderingInterface { MWRender::Shadows* mShadows; MWRender::ShaderHelper* mShaderHelper; + + MWRender::Compositors* mCompositors; }; } diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp index 1d29be2b8..59154a295 100644 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -258,7 +258,7 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s outStream << " float3 lightingFinal = lightColour.xyz * diffuse.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" - " oColor.xyz = lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue); \n" + " oColor.xyz = saturate(lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue)); \n" // saturate output to prevent negative output colors - TODO: replace this once there is HDR-rendering " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index da2e7446a..72f88c6c5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -113,6 +113,7 @@ void BillboardObject::init(const String& textureName, p->setSelfIllumination(1.0,1.0,1.0); p->setDiffuse(0.0,0.0,0.0,1.0); p->setAmbient(0.0,0.0,0.0); + p->setPolygonModeOverrideable(false); p->createTextureUnitState(textureName); mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); @@ -520,6 +521,7 @@ void SkyManager::create() mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); + mp->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); mStarsMaterials[i] = mp; } @@ -535,6 +537,7 @@ void SkyManager::create() mAtmosphereDay = mRootNode->createChildSceneNode(); mAtmosphereDay->attachObject(atmosphere_ent); mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); + mAtmosphereMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); // Atmosphere shader HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -598,6 +601,7 @@ void SkyManager::create() SceneNode* clouds_node = mRootNode->createChildSceneNode(); clouds_node->attachObject(clouds_ent); mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); + mCloudMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); clouds_ent->setCastShadows(false); // Clouds vertex shader diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 840b94e41..dda215999 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -2,24 +2,20 @@ #include #include "sky.hpp" #include "renderingmanager.hpp" +#include "compositors.hpp" using namespace Ogre; namespace MWRender { -Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mReflectionTarget(0), mActive(1), mToggled(1), - mReflectionRenderActive(false) + mReflectionRenderActive(false), mRendering(rend) { - mSky = sky; - - try - { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, "Water", false); - } catch(...) {} + mSky = rend->getSkyManager(); mTop = cell->water; @@ -147,8 +143,6 @@ Water::~Water() mWaterNode->detachObject(mWater); mSceneManager->destroyEntity(mWater); mSceneManager->destroySceneNode(mWaterNode); - - CompositorManager::getSingleton().removeCompositorChain(mViewport); } void Water::changeCell(const ESM::Cell* cell) @@ -178,13 +172,13 @@ void Water::checkUnderwater(float y) { if (!mActive) { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); return; } if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); // tell the shader we are not underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); @@ -199,7 +193,7 @@ void Water::checkUnderwater(float y) if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) { if (mUnderwaterEffect) - CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, true); + mRendering->getCompositors()->setCompositorEnabled(mCompositorName, true); // tell the shader we are underwater Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index c8b8d311e..25631b4af 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,7 @@ namespace MWRender { class SkyManager; + class RenderingManager; /// Water rendering class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener @@ -40,6 +41,7 @@ namespace MWRender { void updateVisible(); + RenderingManager* mRendering; SkyManager* mSky; std::string mCompositorName; @@ -55,7 +57,7 @@ namespace MWRender { int mVisibilityFlags; public: - Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell); + Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); ~Water(); void setActive(bool active); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 0920c72f8..de7248c0c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -146,4 +146,4 @@ op 0x200014f: ForceGreeting op 0x2000150: ForceGreeting, explicit reference op 0x2000151: ToggleFullHelp op 0x2000152: Goodbye -opcodes 0x2000153-0x3ffffff unused +opcodes 0x2000154-0x3ffffff unused diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 26b9fed75..1b0ad7fd8 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -66,7 +66,8 @@ namespace MWWorld { Render_CollisionDebug, Render_Wireframe, - Render_Pathgrid + Render_Pathgrid, + Render_Compositors }; private: diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 05d35b85f..80b2fc469 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -326,6 +326,8 @@ void NIFLoader::createMaterial(const String &name, { material->getTechnique(0)->getPass(0)->setVertexProgram("main_vp"); material->getTechnique(0)->getPass(0)->setFragmentProgram("main_fp"); + + material->getTechnique(0)->getPass(0)->setFog(true); // force-disable fixed function fog, it is calculated in shader } // Create a fallback technique without shadows and without mrt @@ -338,6 +340,7 @@ void NIFLoader::createMaterial(const String &name, { pass2->setVertexProgram("main_fallback_vp"); pass2->setFragmentProgram("main_fallback_fp"); + pass2->setFog(true); // force-disable fixed function fog, it is calculated in shader } // Add material bells and whistles diff --git a/files/shadows/depthshadowcaster.material b/files/shadows/depthshadowcaster.material index 9ff51c5b1..f645cad01 100644 --- a/files/shadows/depthshadowcaster.material +++ b/files/shadows/depthshadowcaster.material @@ -1,67 +1,73 @@ vertex_program depth_shadow_caster_vs cg { - source depthshadowcaster.cg - profiles vs_1_1 arbvp1 - entry_point main_vp + source depthshadowcaster.cg + profiles vs_1_1 arbvp1 + entry_point main_vp - default_params - { - param_named_auto wvpMat worldviewproj_matrix - } + 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 + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp - default_params - { - } + default_params + { + } } fragment_program depth_shadow_caster_ps_noalpha cg { - source depthshadowcaster.cg - profiles ps_2_0 arbfp1 - entry_point main_fp_noalpha + source depthshadowcaster.cg + profiles ps_2_0 arbfp1 + entry_point main_fp_noalpha - default_params - { - } + default_params + { + } } material depth_shadow_caster { - technique - { - pass - { - vertex_program_ref depth_shadow_caster_vs - { - } + technique + { + pass + { + // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) + fog_override true - fragment_program_ref depth_shadow_caster_ps - { - } - } - } + 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 - { - } + technique + { + pass + { + // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) + fog_override true + + vertex_program_ref depth_shadow_caster_vs + { + } - fragment_program_ref depth_shadow_caster_ps_noalpha - { - } - } - } + fragment_program_ref depth_shadow_caster_ps_noalpha + { + } + } + } }