mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 10:49:57 +00:00
1e4a854433
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. :)
1060 lines
34 KiB
C++
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
|