1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 04:49:54 +00:00
openmw-tes3mp/apps/openmw/mwrender/renderingmanager.cpp
Emanuel Guevel 1e4a854433 Remove static method MWWorld::Class::get(&Ptr)
It was just adding a level of indirection to Ptr.getClass().
All the call were replaced by that instead. The number of lines changed
is important, but the change itself is trivial, so everything should be
fine. :)
2014-05-22 20:50:00 +02:00

1060 lines
34 KiB
C++

#include "renderingmanager.hpp"
#include <cassert>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreViewport.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreControllerManager.h>
#include <OgreMeshManager.h>
#include <OgreRenderTexture.h>
#include <SDL_video.h>
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <openengine/bullet/physic.hpp>
#include <components/settings/settings.hpp>
#include <components/terrain/world.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone
#include "../mwbase/environment.hpp"
#include "../mwbase/inputmanager.hpp" // FIXME
#include "../mwbase/windowmanager.hpp" // FIXME
#include "../mwbase/statemanager.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwworld/ptr.hpp"
#include "shadows.hpp"
#include "localmap.hpp"
#include "water.hpp"
#include "npcanimation.hpp"
#include "globalmap.hpp"
#include "terrainstorage.hpp"
#include "effectmanager.hpp"
using namespace MWRender;
using namespace Ogre;
namespace MWRender {
RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir,
const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,
MWWorld::Fallback* fallback)
: mRendering(_rend)
, mFallback(fallback)
, mPlayerAnimation(NULL)
, mAmbientMode(0)
, mSunEnabled(0)
, mPhysicsEngine(engine)
, mTerrain(NULL)
, mEffectManager(NULL)
{
mActors = new MWRender::Actors(mRendering, this);
mObjects = new MWRender::Objects(mRendering);
mEffectManager = new EffectManager(mRendering.getScene());
// select best shader mode
bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos);
bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos);
// glsl is only supported in opengl mode and hlsl only in direct3d mode.
std::string currentMode = Settings::Manager::getString("shader mode", "General");
if (currentMode == ""
|| (openGL && currentMode == "hlsl")
|| (!openGL && currentMode == "glsl")
|| (glES && currentMode != "glsles"))
{
Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl");
}
mRendering.adjustCamera(Settings::Manager::getFloat("field of view", "General"), 5);
mRendering.getWindow()->addListener(this);
mRendering.setWindowListener(this);
mWater = 0;
// material system
sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string());
if (!boost::filesystem::exists (cacheDir))
boost::filesystem::create_directories (cacheDir);
platform->setCacheFolder (cacheDir.string());
mFactory = new sh::Factory(platform);
sh::Language lang;
std::string l = Settings::Manager::getString("shader mode", "General");
if (l == "glsl")
lang = sh::Language_GLSL;
else if (l == "glsles")
lang = sh::Language_GLSLES;
else if (l == "hlsl")
lang = sh::Language_HLSL;
else
lang = sh::Language_CG;
mFactory->setCurrentLanguage (lang);
mFactory->setWriteSourceCache (true);
mFactory->setReadSourceCache (true);
mFactory->setReadMicrocodeCache (true);
mFactory->setWriteMicrocodeCache (true);
mFactory->loadAllFiles();
// Compressed textures with 0 mip maps are bugged in 1.8, so disable mipmap generator in that case
// ( https://ogre3d.atlassian.net/browse/OGRE-259 )
#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General"));
#else
TextureManager::getSingleton().setDefaultNumMipmaps(0);
#endif
// Set default texture filtering options
TextureFilterOptions tfo;
std::string filter = Settings::Manager::getString("texture filtering", "General");
if (filter == "anisotropic") tfo = TFO_ANISOTROPIC;
else if (filter == "trilinear") tfo = TFO_TRILINEAR;
else if (filter == "bilinear") tfo = TFO_BILINEAR;
else /*if (filter == "none")*/ tfo = TFO_NONE;
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024);
Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024);
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
// disable unsupported effects
if (!Settings::Manager::getBool("shaders", "Objects"))
Settings::Manager::setBool("enabled", "Shadows", false);
sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects"));
sh::Factory::getInstance ().setGlobalSetting ("fog", "true");
sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects"));
sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true");
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false");
sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty<sh::FloatValue> (new sh::FloatValue(0.0)));
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(0)));
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(0)));
sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty<sh::Vector3>(new sh::Vector3(0.5, -0.8, 0.2)));
sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty<sh::Vector2>(new sh::Vector2(1, 0.6)));
sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false");
sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false");
sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty<sh::Vector4> (new sh::Vector4(0,0,0,0)));
mRootNode = mRendering.getScene()->getRootSceneNode();
mRootNode->createChildSceneNode("player");
mObjects->setRootNode(mRootNode);
mActors->setRootNode(mRootNode);
mCamera = new MWRender::Camera(mRendering.getCamera());
mShadows = new Shadows(&mRendering);
mSkyManager = new SkyManager(mRootNode, mRendering.getCamera());
mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode());
mSun = 0;
mDebugging = new Debugging(mRootNode, engine);
mLocalMap = new MWRender::LocalMap(&mRendering, this);
mWater = new MWRender::Water(mRendering.getCamera(), this);
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
}
RenderingManager::~RenderingManager ()
{
mRendering.getWindow()->removeListener(this);
delete mPlayerAnimation;
delete mCamera;
delete mSkyManager;
delete mDebugging;
delete mShadows;
delete mTerrain;
delete mLocalMap;
delete mOcclusionQuery;
delete mWater;
delete mActors;
delete mObjects;
delete mEffectManager;
delete mFactory;
}
MWRender::SkyManager* RenderingManager::getSkyManager()
{
return mSkyManager;
}
MWRender::Objects& RenderingManager::getObjects(){
return *mObjects;
}
MWRender::Actors& RenderingManager::getActors(){
return *mActors;
}
OEngine::Render::Fader* RenderingManager::getFader()
{
return mRendering.getFader();
}
MWRender::Camera* RenderingManager::getCamera() const
{
return mCamera;
}
void RenderingManager::removeCell (MWWorld::CellStore *store)
{
mLocalMap->saveFogOfWar(store);
mObjects->removeCell(store);
mActors->removeCell(store);
mDebugging->cellRemoved(store);
}
void RenderingManager::removeWater ()
{
mWater->setActive(false);
}
bool RenderingManager::toggleWater()
{
return mWater->toggle();
}
void RenderingManager::cellAdded (MWWorld::CellStore *store)
{
mObjects->buildStaticGeometry (*store);
sh::Factory::getInstance().unloadUnreferencedMaterials();
mDebugging->cellAdded(store);
waterAdded(store);
}
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
const MWWorld::Class& class_ =
ptr.getClass();
class_.insertObjectRendering(ptr, *this);
}
void RenderingManager::removeObject (const MWWorld::Ptr& ptr)
{
if (!mObjects->deleteObject (ptr))
mActors->deleteObject (ptr);
}
void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position)
{
/// \todo move this to the rendering-subsystems
ptr.getRefData().getBaseNode()->setPosition(position);
}
void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale)
{
ptr.getRefData().getBaseNode()->setScale(scale);
}
void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
{
Ogre::Vector3 rot(ptr.getRefData().getPosition().rot);
if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
!mCamera->isVanityOrPreviewModeEnabled())
mCamera->rotateCamera(-rot, false);
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z);
if(!ptr.getClass().isActor())
newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) *
Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo;
ptr.getRefData().getBaseNode()->setOrientation(newo);
}
void
RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur)
{
Ogre::SceneNode *child =
mRendering.getScene()->getSceneNode(old.getRefData().getHandle());
Ogre::SceneNode *parent = child->getParentSceneNode();
parent->removeChild(child);
if (old.getClass().isActor()) {
mActors->updateObjectCell(old, cur);
} else {
mObjects->updateObjectCell(old, cur);
}
}
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
{
if(mPlayerAnimation)
mPlayerAnimation->updatePtr(ptr);
if(mCamera->getHandle() == ptr.getRefData().getHandle())
mCamera->attachTo(ptr);
}
void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
{
NpcAnimation *anim = NULL;
if(ptr.getRefData().getHandle() == "player")
anim = mPlayerAnimation;
else if(ptr.getClass().isActor())
anim = dynamic_cast<NpcAnimation*>(mActors->getAnimation(ptr));
if(anim)
{
anim->rebuild();
if(mCamera->getHandle() == ptr.getRefData().getHandle())
{
mCamera->attachTo(ptr);
mCamera->setAnimation(anim);
}
}
}
void RenderingManager::update (float duration, bool paused)
{
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_NoGame)
return;
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).mMagnitude;
mRendering.getFader()->setFactor(std::max(0.f, 1.f-(blind / 100.f)));
setAmbientMode();
// player position
MWWorld::RefData &data = player.getRefData();
Ogre::Vector3 playerPos(data.getPosition().pos);
mCamera->setCameraDistance();
if(!mCamera->isFirstPerson())
{
Ogre::Vector3 orig, dest;
mCamera->getPosition(orig, dest);
btVector3 btOrig(orig.x, orig.y, orig.z);
btVector3 btDest(dest.x, dest.y, dest.z);
std::pair<bool,float> test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest);
if(test.first)
mCamera->setCameraDistance(test.second * orig.distance(dest), false, false);
}
// Sink the camera while sneaking
bool isSneaking = player.getClass().getCreatureStats(player).getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool isInAir = !world->isOnGround(player);
bool isSwimming = world->isSwimming(player);
static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("i1stPersonSneakDelta")->getInt();
if(!paused && isSneaking && !(isSwimming || isInAir))
mCamera->setSneakOffset(i1stPersonSneakDelta);
mOcclusionQuery->update(duration);
mRendering.update(duration);
Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f);
Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition();
applyFog(world->isUnderwater(player.getCell(), cam));
mCamera->update(duration, paused);
Ogre::SceneNode *node = data.getBaseNode();
Ogre::Quaternion orient = node->_getDerivedOrientation();
mLocalMap->updatePlayer(playerPos, orient);
if(paused)
return;
mEffectManager->update(duration, mRendering.getCamera());
mActors->update (mRendering.getCamera());
mPlayerAnimation->preRender(mRendering.getCamera());
mObjects->update (duration, mRendering.getCamera());
mSkyManager->update(duration);
mSkyManager->setGlare(mOcclusionQuery->getSunVisibility());
mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam));
mWater->update(duration, playerPos);
}
void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt)
{
mOcclusionQuery->setActive(true);
}
void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt)
{
// deactivate queries to make sure we aren't getting false results from several misc render targets
// (will be reactivated at the bottom of this method)
mOcclusionQuery->setActive(false);
}
void RenderingManager::waterAdded (MWWorld::CellStore *store)
{
if (store->getCell()->mData.mFlags & ESM::Cell::HasWater)
{
mWater->changeCell (store->getCell());
mWater->setActive(true);
}
else
removeWater();
}
void RenderingManager::setWaterHeight(const float height)
{
mWater->setHeight(height);
}
void RenderingManager::skyEnable ()
{
mSkyManager->enable();
mOcclusionQuery->setSunNode(mSkyManager->getSunNode());
}
void RenderingManager::skyDisable ()
{
mSkyManager->disable();
}
void RenderingManager::skySetHour (double hour)
{
mSkyManager->setHour(hour);
}
void RenderingManager::skySetDate (int day, int month)
{
mSkyManager->setDate(day, month);
}
int RenderingManager::skyGetMasserPhase() const
{
return mSkyManager->getMasserPhase();
}
int RenderingManager::skyGetSecundaPhase() const
{
return mSkyManager->getSecundaPhase();
}
void RenderingManager::skySetMoonColour (bool red){
mSkyManager->setMoonColour(red);
}
bool RenderingManager::toggleRenderMode(int mode)
{
if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid)
return mDebugging->toggleRenderMode(mode);
else if (mode == MWBase::World::Render_Wireframe)
{
if (mRendering.getCamera()->getPolygonMode() == PM_SOLID)
{
mRendering.getCamera()->setPolygonMode(PM_WIREFRAME);
return true;
}
else
{
mRendering.getCamera()->setPolygonMode(PM_SOLID);
return false;
}
}
else //if (mode == MWBase::World::Render_BoundingBoxes)
{
bool show = !mRendering.getScene()->getShowBoundingBoxes();
mRendering.getScene()->showBoundingBoxes(show);
return show;
}
}
void RenderingManager::configureFog(MWWorld::CellStore &mCell)
{
Ogre::ColourValue color;
color.setAsABGR (mCell.getCell()->mAmbi.mFog);
configureFog (mCell.getCell()->mAmbi.mFogDensity, color);
}
void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour)
{
mFogColour = colour;
float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance");
mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance");
mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance");
mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density );
}
void RenderingManager::applyFog (bool underwater)
{
if (!underwater)
{
mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd);
mRendering.getViewport()->setBackgroundColour (mFogColour);
mWater->setViewportBackground (mFogColour);
}
else
{
mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(0.18039, 0.23137, 0.25490), 0, 0, 1000);
mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(0.18039, 0.23137, 0.25490));
mWater->setViewportBackground (Ogre::ColourValue(0.18039, 0.23137, 0.25490));
}
}
void RenderingManager::setAmbientMode()
{
switch (mAmbientMode)
{
case 0:
setAmbientColour(mAmbientColor);
break;
case 1:
setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1));
break;
case 2:
setAmbientColour(ColourValue(1,1,1));
break;
}
}
void RenderingManager::configureAmbient(MWWorld::CellStore &mCell)
{
if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior)
mAmbientColor.setAsABGR (mCell.getCell()->mAmbi.mAmbient);
setAmbientMode();
// Create a "sun" that shines light downwards. It doesn't look
// completely right, but leave it for now.
if(!mSun)
{
mSun = mRendering.getScene()->createLight();
mSun->setType(Ogre::Light::LT_DIRECTIONAL);
}
if (mCell.getCell()->mData.mFlags & ESM::Cell::Interior)
{
Ogre::ColourValue colour;
colour.setAsABGR (mCell.getCell()->mAmbi.mSunlight);
mSun->setDiffuseColour (colour);
mSun->setDirection(1,-1,-1);
sunEnable(false);
}
}
// Switch through lighting modes.
void RenderingManager::toggleLight()
{
if (mAmbientMode==2)
mAmbientMode = 0;
else
++mAmbientMode;
switch (mAmbientMode)
{
case 0: std::cout << "Setting lights to normal\n"; break;
case 1: std::cout << "Turning the lights up\n"; break;
case 2: std::cout << "Turning the lights to full\n"; break;
}
setAmbientMode();
}
void RenderingManager::setSunColour(const Ogre::ColourValue& colour)
{
if (!mSunEnabled) return;
mSun->setDiffuseColour(colour);
mSun->setSpecularColour(colour);
}
void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour)
{
mAmbientColor = colour;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int nightEye = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).mMagnitude;
Ogre::ColourValue final = colour;
final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f));
mRendering.getScene()->setAmbientLight(final);
}
void RenderingManager::sunEnable(bool real)
{
if (real && mSun) mSun->setVisible(true);
else
{
// Don't disable the light, as the shaders assume the first light to be directional.
mSunEnabled = true;
}
}
void RenderingManager::sunDisable(bool real)
{
if (real && mSun) mSun->setVisible(false);
else
{
// Don't disable the light, as the shaders assume the first light to be directional.
mSunEnabled = false;
if (mSun)
{
mSun->setDiffuseColour(ColourValue(0,0,0));
mSun->setSpecularColour(ColourValue(0,0,0));
}
}
}
void RenderingManager::setSunDirection(const Ogre::Vector3& direction)
{
// direction * -1 (because 'direction' is camera to sun vector and not sun to camera),
if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z));
mSkyManager->setSunDirection(direction);
}
void RenderingManager::setGlare(bool glare)
{
mSkyManager->setGlare(glare);
}
void RenderingManager::updateTerrain()
{
if (mTerrain)
{
// Avoid updating with dims.getCenter for each cell. Player position should be good enough
mTerrain->update(mRendering.getCamera()->getRealPosition());
mTerrain->syncLoad();
// need to update again so the chunks that were just loaded can be made visible
mTerrain->update(mRendering.getCamera()->getRealPosition());
}
}
void RenderingManager::requestMap(MWWorld::CellStore* cell)
{
if (cell->getCell()->isExterior())
{
assert(mTerrain);
Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell);
Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5);
dims.merge(mTerrain->getWorldBoundingBox(center));
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
}
else
mLocalMap->requestMap(cell, mObjects->getDimensions(cell));
}
void RenderingManager::writeFog(MWWorld::CellStore* cell)
{
mLocalMap->saveFogOfWar(cell);
}
void RenderingManager::disableLights(bool sun)
{
mObjects->disableLights();
sunDisable(sun);
}
void RenderingManager::enableLights(bool sun)
{
mObjects->enableLights();
sunEnable(sun);
}
Shadows* RenderingManager::getShadows()
{
return mShadows;
}
void RenderingManager::notifyWorldSpaceChanged()
{
mEffectManager->clear();
}
Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds)
{
Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix();
const Ogre::Vector3* corners = bounds.getAllCorners();
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
// 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
// get a camera-space vertex
corner = mat * corner;
// make 2D relative/normalized coords from the view-space vertex
// by dividing out the Z (depth) factor -- this is an approximation
float x = corner.x / corner.z + 0.5;
float y = corner.y / corner.z + 0.5;
if (x < min_x)
min_x = x;
if (x > max_x)
max_x = x;
if (y < min_y)
min_y = y;
if (y > max_y)
max_y = y;
}
return Vector4(min_x, min_y, max_x, max_y);
}
void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings)
{
bool changeRes = false;
bool rebuild = false; // rebuild static geometry (necessary after any material changes)
for (Settings::CategorySettingVector::const_iterator it=settings.begin();
it != settings.end(); ++it)
{
if (it->second == "menu transparency" && it->first == "GUI")
{
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
}
else if (it->second == "max viewing distance" && it->first == "Viewing distance")
{
if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior())
configureFog(*MWBase::Environment::get().getWorld()->getPlayerPtr().getCell());
}
else if (it->first == "Video" && (
it->second == "resolution x"
|| it->second == "resolution y"
|| it->second == "fullscreen"))
changeRes = true;
else if (it->first == "Video" && it->second == "vsync")
{
// setVSyncEnabled is bugged in 1.8
#if OGRE_VERSION >= (1 << 16 | 9 << 8 | 0)
mRendering.getWindow()->setVSyncEnabled(Settings::Manager::getBool("vsync", "Video"));
#endif
}
else if (it->second == "field of view" && it->first == "General")
mRendering.setFov(Settings::Manager::getFloat("field of view", "General"));
else if ((it->second == "texture filtering" && it->first == "General")
|| (it->second == "anisotropy" && it->first == "General"))
{
TextureFilterOptions tfo;
std::string filter = Settings::Manager::getString("texture filtering", "General");
if (filter == "anisotropic") tfo = TFO_ANISOTROPIC;
else if (filter == "trilinear") tfo = TFO_TRILINEAR;
else if (filter == "bilinear") tfo = TFO_BILINEAR;
else /*if (filter == "none")*/ tfo = TFO_NONE;
MaterialManager::getSingleton().setDefaultTextureFiltering(tfo);
MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 );
}
else if (it->second == "shader" && it->first == "Water")
{
sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true");
rebuild = true;
mRendering.getViewport ()->setClearEveryFrame (true);
}
else if (it->second == "refraction" && it->first == "Water")
{
sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false");
rebuild = true;
}
else if (it->second == "shaders" && it->first == "Objects")
{
sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects"));
rebuild = true;
}
else if (it->second == "shader mode" && it->first == "General")
{
sh::Language lang;
std::string l = Settings::Manager::getString("shader mode", "General");
if (l == "glsl")
lang = sh::Language_GLSL;
else if (l == "hlsl")
lang = sh::Language_HLSL;
else
lang = sh::Language_CG;
sh::Factory::getInstance ().setCurrentLanguage (lang);
rebuild = true;
}
else if (it->first == "Shadows")
{
mShadows->recreate ();
rebuild = true;
}
}
if (changeRes)
{
unsigned int x = Settings::Manager::getInt("resolution x", "Video");
unsigned int y = Settings::Manager::getInt("resolution y", "Video");
bool fullscreen = Settings::Manager::getBool("fullscreen", "Video");
SDL_Window* window = mRendering.getSDLWindow();
SDL_SetWindowFullscreen(window, 0);
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MAXIMIZED)
SDL_RestoreWindow(window);
if (fullscreen)
{
SDL_DisplayMode mode;
SDL_GetWindowDisplayMode(window, &mode);
mode.w = x;
mode.h = y;
SDL_SetWindowDisplayMode(window, &mode);
SDL_SetWindowFullscreen(window, fullscreen);
}
else
SDL_SetWindowSize(window, x, y);
}
mWater->processChangedSettings(settings);
if (rebuild)
{
mObjects->rebuildStaticGeometry();
if (mTerrain)
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows"));
}
}
void RenderingManager::setMenuTransparency(float val)
{
Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName("transparent.png");
std::vector<Ogre::uint32> buffer;
buffer.resize(1);
buffer[0] = (int(255*val) << 24);
memcpy(tex->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], 1*4);
tex->getBuffer()->unlock();
}
void RenderingManager::windowResized(int x, int y)
{
Settings::Manager::setInt("resolution x", "Video", x);
Settings::Manager::setInt("resolution y", "Video", y);
mRendering.adjustViewport();
MWBase::Environment::get().getWindowManager()->windowResized(x,y);
}
void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches)
{
batches = mRendering.getWindow()->getBatchCount();
triangles = mRendering.getWindow()->getTriangleCount();
}
void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr)
{
ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player"));
mCamera->attachTo(ptr);
}
void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr)
{
if(!mPlayerAnimation)
{
mPlayerAnimation = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
}
else
{
// Reconstruct the NpcAnimation in-place
mPlayerAnimation->~NpcAnimation();
new(mPlayerAnimation) NpcAnimation(ptr, ptr.getRefData().getBaseNode(), RV_Actors);
}
mCamera->setAnimation(mPlayerAnimation);
mWater->removeEmitter(ptr);
mWater->addEmitter(ptr);
// apply race height
MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f);
}
bool RenderingManager::vanityRotateCamera(const float *rot)
{
if(!mCamera->isVanityOrPreviewModeEnabled())
return false;
Ogre::Vector3 vRot(rot);
mCamera->rotateCamera(vRot, true);
return true;
}
void RenderingManager::setCameraDistance(float dist, bool adjust, bool override)
{
if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson())
{
if(mCamera->isNearest() && dist > 0.f)
mCamera->toggleViewMode();
else
mCamera->setCameraDistance(-dist / 120.f * 10, adjust, override);
}
else if(mCamera->isFirstPerson() && dist < 0.f)
{
mCamera->toggleViewMode();
mCamera->setCameraDistance(0.f, false, override);
}
}
void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y)
{
return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y);
}
bool RenderingManager::isPositionExplored (float nX, float nY, int x, int y, bool interior)
{
return mLocalMap->isPositionExplored(nX, nY, x, y, interior);
}
Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
{
Animation *anim = mActors->getAnimation(ptr);
if(!anim && ptr.getRefData().getHandle() == "player")
anim = mPlayerAnimation;
if (!anim)
anim = mObjects->getAnimation(ptr);
return anim;
}
void RenderingManager::screenshot(Image &image, int w, int h)
{
// Create a temporary render target. We do not use the RenderWindow since we want a specific size.
// Also, the GUI should not be visible (and it is only rendered on the RenderWindow's primary viewport)
const std::string tempName = "@temp";
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(tempName,
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, w, h, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
float oldAspect = mRendering.getCamera()->getAspectRatio();
mRendering.getCamera()->setAspectRatio(w / static_cast<float>(h));
Ogre::RenderTarget* rt = texture->getBuffer()->getRenderTarget();
Ogre::Viewport* vp = rt->addViewport(mRendering.getCamera());
vp->setBackgroundColour(mRendering.getViewport()->getBackgroundColour());
vp->setOverlaysEnabled(false);
vp->setVisibilityMask(mRendering.getViewport()->getVisibilityMask());
rt->update();
Ogre::PixelFormat pf = rt->suggestPixelFormat();
image.loadDynamicImage(
OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL),
w, h, 1, pf, true // autoDelete=true, frees memory we allocate
);
rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image
Ogre::TextureManager::getSingleton().remove(tempName);
mRendering.getCamera()->setAspectRatio(oldAspect);
}
void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force)
{
mWater->addEmitter (ptr, scale, force);
}
void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr)
{
mWater->removeEmitter (ptr);
}
void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
{
mWater->updateEmitterPtr(old, ptr);
}
void RenderingManager::frameStarted(float dt, bool paused)
{
if (mTerrain)
mTerrain->update(mRendering.getCamera()->getRealPosition());
if (!paused)
mWater->frameStarted(dt);
}
void RenderingManager::resetCamera()
{
mCamera->reset();
}
float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos)
{
if (!mTerrain || !mTerrain->getVisible())
return -std::numeric_limits<float>::max();
return mTerrain->getHeightAt(worldPos);
}
void RenderingManager::enableTerrain(bool enable)
{
if (enable)
{
if (!mTerrain)
{
mTerrain = new Terrain::World(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
Settings::Manager::getBool("distant land", "Terrain"),
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64);
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows"));
mTerrain->update(mRendering.getCamera()->getRealPosition());
}
mTerrain->setVisible(true);
}
else if (mTerrain)
mTerrain->setVisible(false);
}
float RenderingManager::getCameraDistance() const
{
return mCamera->getCameraDistance();
}
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale)
{
mEffectManager->addEffect(model, texture, worldPosition, scale);
}
void RenderingManager::clear()
{
mLocalMap->clear();
notifyWorldSpaceChanged();
}
} // namespace