1 #include "renderingmanager.hpp" 2 3 #include <limits> 4 #include <cstdlib> 5 6 #include <osg/Light> 7 #include <osg/LightModel> 8 #include <osg/Fog> 9 #include <osg/Material> 10 #include <osg/PolygonMode> 11 #include <osg/Group> 12 #include <osg/UserDataContainer> 13 #include <osg/ComputeBoundsVisitor> 14 15 #include <osgUtil/LineSegmentIntersector> 16 17 #include <osgViewer/Viewer> 18 19 #include <components/nifosg/nifloader.hpp> 20 21 #include <components/debug/debuglog.hpp> 22 23 #include <components/resource/resourcesystem.hpp> 24 #include <components/resource/imagemanager.hpp> 25 #include <components/resource/scenemanager.hpp> 26 #include <components/resource/keyframemanager.hpp> 27 28 #include <components/shader/removedalphafunc.hpp> 29 #include <components/shader/shadermanager.hpp> 30 31 #include <components/settings/settings.hpp> 32 33 #include <components/sceneutil/util.hpp> 34 #include <components/sceneutil/lightmanager.hpp> 35 #include <components/sceneutil/statesetupdater.hpp> 36 #include <components/sceneutil/positionattitudetransform.hpp> 37 #include <components/sceneutil/workqueue.hpp> 38 #include <components/sceneutil/unrefqueue.hpp> 39 #include <components/sceneutil/writescene.hpp> 40 #include <components/sceneutil/shadow.hpp> 41 42 #include <components/terrain/terraingrid.hpp> 43 #include <components/terrain/quadtreeworld.hpp> 44 45 #include <components/esm/loadcell.hpp> 46 47 #include <components/detournavigator/navigator.hpp> 48 49 #include "../mwworld/cellstore.hpp" 50 #include "../mwworld/class.hpp" 51 #include "../mwgui/loadingscreen.hpp" 52 #include "../mwbase/windowmanager.hpp" 53 #include "../mwmechanics/actorutil.hpp" 54 55 #include "sky.hpp" 56 #include "effectmanager.hpp" 57 #include "npcanimation.hpp" 58 #include "vismask.hpp" 59 #include "pathgrid.hpp" 60 #include "camera.hpp" 61 #include "viewovershoulder.hpp" 62 #include "water.hpp" 63 #include "terrainstorage.hpp" 64 #include "navmesh.hpp" 65 #include "actorspaths.hpp" 66 #include "recastmesh.hpp" 67 #include "fogmanager.hpp" 68 #include "objectpaging.hpp" 69 #include "screenshotmanager.hpp" 70 #include "groundcover.hpp" 71 72 namespace MWRender 73 { 74 75 class StateUpdater : public SceneUtil::StateSetUpdater 76 { 77 public: StateUpdater()78 StateUpdater() 79 : mFogStart(0.f) 80 , mFogEnd(0.f) 81 , mWireframe(false) 82 { 83 } 84 setDefaults(osg::StateSet * stateset)85 void setDefaults(osg::StateSet *stateset) override 86 { 87 osg::LightModel* lightModel = new osg::LightModel; 88 stateset->setAttribute(lightModel, osg::StateAttribute::ON); 89 osg::Fog* fog = new osg::Fog; 90 fog->setMode(osg::Fog::LINEAR); 91 stateset->setAttributeAndModes(fog, osg::StateAttribute::ON); 92 if (mWireframe) 93 { 94 osg::PolygonMode* polygonmode = new osg::PolygonMode; 95 polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); 96 stateset->setAttributeAndModes(polygonmode, osg::StateAttribute::ON); 97 } 98 else 99 stateset->removeAttribute(osg::StateAttribute::POLYGONMODE); 100 } 101 apply(osg::StateSet * stateset,osg::NodeVisitor *)102 void apply(osg::StateSet* stateset, osg::NodeVisitor*) override 103 { 104 osg::LightModel* lightModel = static_cast<osg::LightModel*>(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); 105 lightModel->setAmbientIntensity(mAmbientColor); 106 osg::Fog* fog = static_cast<osg::Fog*>(stateset->getAttribute(osg::StateAttribute::FOG)); 107 fog->setColor(mFogColor); 108 fog->setStart(mFogStart); 109 fog->setEnd(mFogEnd); 110 } 111 setAmbientColor(const osg::Vec4f & col)112 void setAmbientColor(const osg::Vec4f& col) 113 { 114 mAmbientColor = col; 115 } 116 setFogColor(const osg::Vec4f & col)117 void setFogColor(const osg::Vec4f& col) 118 { 119 mFogColor = col; 120 } 121 setFogStart(float start)122 void setFogStart(float start) 123 { 124 mFogStart = start; 125 } 126 setFogEnd(float end)127 void setFogEnd(float end) 128 { 129 mFogEnd = end; 130 } 131 setWireframe(bool wireframe)132 void setWireframe(bool wireframe) 133 { 134 if (mWireframe != wireframe) 135 { 136 mWireframe = wireframe; 137 reset(); 138 } 139 } 140 getWireframe() const141 bool getWireframe() const 142 { 143 return mWireframe; 144 } 145 146 private: 147 osg::Vec4f mAmbientColor; 148 osg::Vec4f mFogColor; 149 float mFogStart; 150 float mFogEnd; 151 bool mWireframe; 152 }; 153 154 class PreloadCommonAssetsWorkItem : public SceneUtil::WorkItem 155 { 156 public: PreloadCommonAssetsWorkItem(Resource::ResourceSystem * resourceSystem)157 PreloadCommonAssetsWorkItem(Resource::ResourceSystem* resourceSystem) 158 : mResourceSystem(resourceSystem) 159 { 160 } 161 doWork()162 void doWork() override 163 { 164 try 165 { 166 for (std::vector<std::string>::const_iterator it = mModels.begin(); it != mModels.end(); ++it) 167 mResourceSystem->getSceneManager()->cacheInstance(*it); 168 for (std::vector<std::string>::const_iterator it = mTextures.begin(); it != mTextures.end(); ++it) 169 mResourceSystem->getImageManager()->getImage(*it); 170 for (std::vector<std::string>::const_iterator it = mKeyframes.begin(); it != mKeyframes.end(); ++it) 171 mResourceSystem->getKeyframeManager()->get(*it); 172 } 173 catch (std::exception&) 174 { 175 // ignore error (will be shown when these are needed proper) 176 } 177 } 178 179 std::vector<std::string> mModels; 180 std::vector<std::string> mTextures; 181 std::vector<std::string> mKeyframes; 182 183 private: 184 Resource::ResourceSystem* mResourceSystem; 185 }; 186 RenderingManager(osgViewer::Viewer * viewer,osg::ref_ptr<osg::Group> rootNode,Resource::ResourceSystem * resourceSystem,SceneUtil::WorkQueue * workQueue,const std::string & resourcePath,DetourNavigator::Navigator & navigator)187 RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, 188 Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, 189 const std::string& resourcePath, DetourNavigator::Navigator& navigator) 190 : mViewer(viewer) 191 , mRootNode(rootNode) 192 , mResourceSystem(resourceSystem) 193 , mWorkQueue(workQueue) 194 , mUnrefQueue(new SceneUtil::UnrefQueue) 195 , mNavigator(navigator) 196 , mMinimumAmbientLuminance(0.f) 197 , mNightEyeFactor(0.f) 198 , mFieldOfViewOverridden(false) 199 , mFieldOfViewOverride(0.f) 200 { 201 auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders")); 202 203 resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); 204 resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); 205 // Shadows and radial fog have problems with fixed-function mode 206 bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders") 207 || Settings::Manager::getBool("force shaders", "Shaders") 208 || Settings::Manager::getBool("enable shadows", "Shadows") 209 || lightingMethod != SceneUtil::LightingMethod::FFP; 210 resourceSystem->getSceneManager()->setForceShaders(forceShaders); 211 // FIXME: calling dummy method because terrain needs to know whether lighting is clamped 212 resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); 213 resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); 214 resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders")); 215 resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders")); 216 resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders")); 217 resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders")); 218 resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders")); 219 resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1); 220 221 // Let LightManager choose which backend to use based on our hint. For methods besides legacy lighting, this depends on support for various OpenGL extensions. 222 osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP); 223 resourceSystem->getSceneManager()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod()); 224 resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod()); 225 resourceSystem->getSceneManager()->setSupportedLightingMethods(sceneRoot->getSupportedLightingMethods()); 226 mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); 227 228 sceneRoot->setLightingMask(Mask_Lighting); 229 mSceneRoot = sceneRoot; 230 sceneRoot->setStartLight(1); 231 sceneRoot->setNodeMask(Mask_Scene); 232 sceneRoot->setName("Scene Root"); 233 234 int shadowCastingTraversalMask = Mask_Scene; 235 if (Settings::Manager::getBool("actor shadows", "Shadows")) 236 shadowCastingTraversalMask |= Mask_Actor; 237 if (Settings::Manager::getBool("player shadows", "Shadows")) 238 shadowCastingTraversalMask |= Mask_Player; 239 if (Settings::Manager::getBool("terrain shadows", "Shadows")) 240 shadowCastingTraversalMask |= Mask_Terrain; 241 242 int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; 243 if (Settings::Manager::getBool("object shadows", "Shadows")) 244 shadowCastingTraversalMask |= (Mask_Object|Mask_Static); 245 246 mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); 247 248 Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); 249 Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines(); 250 Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); 251 252 for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) 253 globalDefines[itr->first] = itr->second; 254 255 globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; 256 globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; 257 globalDefines["preLightEnv"] = Settings::Manager::getBool("apply lighting to environment maps", "Shaders") ? "1" : "0"; 258 globalDefines["radialFog"] = Settings::Manager::getBool("radial fog", "Shaders") ? "1" : "0"; 259 globalDefines["useGPUShader4"] = "0"; 260 261 for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++) 262 globalDefines[itr->first] = itr->second; 263 264 // Refactor this at some point - most shaders don't care about these defines 265 float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); 266 globalDefines["groundcoverFadeStart"] = std::to_string(groundcoverDistance * 0.9f); 267 globalDefines["groundcoverFadeEnd"] = std::to_string(groundcoverDistance); 268 globalDefines["groundcoverStompMode"] = std::to_string(std::clamp(Settings::Manager::getInt("stomp mode", "Groundcover"), 0, 2)); 269 globalDefines["groundcoverStompIntensity"] = std::to_string(std::clamp(Settings::Manager::getInt("stomp intensity", "Groundcover"), 0, 2)); 270 271 // It is unnecessary to stop/start the viewer as no frames are being rendered yet. 272 mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); 273 274 mNavMesh.reset(new NavMesh(mRootNode, Settings::Manager::getBool("enable nav mesh render", "Navigator"))); 275 mActorsPaths.reset(new ActorsPaths(mRootNode, Settings::Manager::getBool("enable agents paths render", "Navigator"))); 276 mRecastMesh.reset(new RecastMesh(mRootNode, Settings::Manager::getBool("enable recast mesh render", "Navigator"))); 277 mPathgrid.reset(new Pathgrid(mRootNode)); 278 279 mObjects.reset(new Objects(mResourceSystem, sceneRoot, mUnrefQueue.get())); 280 281 if (getenv("OPENMW_DONT_PRECOMPILE") == nullptr) 282 { 283 mViewer->setIncrementalCompileOperation(new osgUtil::IncrementalCompileOperation); 284 mViewer->getIncrementalCompileOperation()->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); 285 } 286 287 mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); 288 289 mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem)); 290 291 const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders"); 292 const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders"); 293 const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders"); 294 const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders"); 295 const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders"); 296 297 mTerrainStorage.reset(new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps)); 298 const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); 299 300 if (Settings::Manager::getBool("distant terrain", "Terrain")) 301 { 302 const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain"); 303 int compMapPower = Settings::Manager::getInt("composite map level", "Terrain"); 304 compMapPower = std::max(-3, compMapPower); 305 float compMapLevel = pow(2, compMapPower); 306 const int vertexLodMod = Settings::Manager::getInt("vertex lod mod", "Terrain"); 307 float maxCompGeometrySize = Settings::Manager::getFloat("max composite geometry size", "Terrain"); 308 maxCompGeometrySize = std::max(maxCompGeometrySize, 1.f); 309 mTerrain.reset(new Terrain::QuadTreeWorld( 310 sceneRoot, mRootNode, mResourceSystem, mTerrainStorage.get(), Mask_Terrain, Mask_PreCompile, Mask_Debug, 311 compMapResolution, compMapLevel, lodFactor, vertexLodMod, maxCompGeometrySize)); 312 if (Settings::Manager::getBool("object paging", "Terrain")) 313 { 314 mObjectPaging.reset(new ObjectPaging(mResourceSystem->getSceneManager())); 315 static_cast<Terrain::QuadTreeWorld*>(mTerrain.get())->addChunkManager(mObjectPaging.get()); 316 mResourceSystem->addResourceManager(mObjectPaging.get()); 317 } 318 } 319 else 320 mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage.get(), Mask_Terrain, Mask_PreCompile, Mask_Debug)); 321 322 mTerrain->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); 323 mTerrain->setWorkQueue(mWorkQueue.get()); 324 325 if (Settings::Manager::getBool("enabled", "Groundcover")) 326 { 327 osg::ref_ptr<osg::Group> groundcoverRoot = new osg::Group; 328 groundcoverRoot->setNodeMask(Mask_Groundcover); 329 groundcoverRoot->setName("Groundcover Root"); 330 sceneRoot->addChild(groundcoverRoot); 331 332 mGroundcoverUpdater = new GroundcoverUpdater; 333 groundcoverRoot->addUpdateCallback(mGroundcoverUpdater); 334 335 float chunkSize = Settings::Manager::getFloat("min chunk size", "Groundcover"); 336 if (chunkSize >= 1.0f) 337 chunkSize = 1.0f; 338 else if (chunkSize >= 0.5f) 339 chunkSize = 0.5f; 340 else if (chunkSize >= 0.25f) 341 chunkSize = 0.25f; 342 else if (chunkSize != 0.125f) 343 chunkSize = 0.125f; 344 345 float density = Settings::Manager::getFloat("density", "Groundcover"); 346 density = std::clamp(density, 0.f, 1.f); 347 348 mGroundcoverWorld.reset(new Terrain::QuadTreeWorld(groundcoverRoot, mTerrainStorage.get(), Mask_Groundcover, lodFactor, chunkSize)); 349 mGroundcover.reset(new Groundcover(mResourceSystem->getSceneManager(), density)); 350 static_cast<Terrain::QuadTreeWorld*>(mGroundcoverWorld.get())->addChunkManager(mGroundcover.get()); 351 mResourceSystem->addResourceManager(mGroundcover.get()); 352 353 // Groundcover it is handled in the same way indifferently from if it is from active grid or from distant cell. 354 // Use a stub grid to avoid splitting between chunks for active grid and chunks for distant cells. 355 mGroundcoverWorld->setActiveGrid(osg::Vec4i(0, 0, 0, 0)); 356 } 357 // water goes after terrain for correct waterculling order 358 mWater.reset(new Water(sceneRoot->getParent(0), sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath)); 359 360 mCamera.reset(new Camera(mViewer->getCamera())); 361 if (Settings::Manager::getBool("view over shoulder", "Camera")) 362 mViewOverShoulderController.reset(new ViewOverShoulderController(mCamera.get())); 363 364 mScreenshotManager.reset(new ScreenshotManager(viewer, mRootNode, sceneRoot, mResourceSystem, mWater.get())); 365 366 mViewer->setLightingMode(osgViewer::View::NO_LIGHT); 367 368 osg::ref_ptr<osg::LightSource> source = new osg::LightSource; 369 source->setNodeMask(Mask_Lighting); 370 mSunLight = new osg::Light; 371 source->setLight(mSunLight); 372 mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); 373 mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); 374 mSunLight->setSpecular(osg::Vec4f(0,0,0,0)); 375 mSunLight->setConstantAttenuation(1.f); 376 sceneRoot->setSunlight(mSunLight); 377 sceneRoot->addChild(source); 378 379 sceneRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); 380 sceneRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); 381 sceneRoot->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); 382 osg::ref_ptr<osg::Material> defaultMat (new osg::Material); 383 defaultMat->setColorMode(osg::Material::OFF); 384 defaultMat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); 385 defaultMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); 386 defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); 387 sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat); 388 389 mFog.reset(new FogManager()); 390 391 mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager())); 392 mSky->setCamera(mViewer->getCamera()); 393 394 source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); 395 396 mStateUpdater = new StateUpdater; 397 sceneRoot->addUpdateCallback(mStateUpdater); 398 399 osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING; 400 401 if (!Settings::Manager::getBool("small feature culling", "Camera")) 402 cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); 403 else 404 { 405 mViewer->getCamera()->setSmallFeatureCullingPixelSize(Settings::Manager::getFloat("small feature culling pixel size", "Camera")); 406 cullingMode |= osg::CullStack::SMALL_FEATURE_CULLING; 407 } 408 409 mViewer->getCamera()->setCullingMode( cullingMode ); 410 411 mViewer->getCamera()->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); 412 mViewer->getCamera()->setCullingMode(cullingMode); 413 414 mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); 415 NifOsg::Loader::setHiddenNodeMask(Mask_UpdateVisitor); 416 NifOsg::Loader::setIntersectionDisabledNodeMask(Mask_Effect); 417 Nif::NIFFile::setLoadUnsupportedFiles(Settings::Manager::getBool("load unsupported nif files", "Models")); 418 419 mNearClip = Settings::Manager::getFloat("near clip", "Camera"); 420 mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); 421 float fov = Settings::Manager::getFloat("field of view", "Camera"); 422 mFieldOfView = std::min(std::max(1.f, fov), 179.f); 423 float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera"); 424 mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f); 425 mStateUpdater->setFogEnd(mViewDistance); 426 427 mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); 428 mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); 429 mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("simpleWater", false)); 430 431 // Hopefully, anything genuinely requiring the default alpha func of GL_ALWAYS explicitly sets it 432 mRootNode->getOrCreateStateSet()->setAttribute(Shader::RemovedAlphaFunc::getInstance(GL_ALWAYS)); 433 // The transparent renderbin sets alpha testing on because that was faster on old GPUs. It's now slower and breaks things. 434 mRootNode->getOrCreateStateSet()->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF); 435 436 mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); 437 mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); 438 updateProjectionMatrix(); 439 } 440 ~RenderingManager()441 RenderingManager::~RenderingManager() 442 { 443 // let background loading thread finish before we delete anything else 444 mWorkQueue = nullptr; 445 } 446 getIncrementalCompileOperation()447 osgUtil::IncrementalCompileOperation* RenderingManager::getIncrementalCompileOperation() 448 { 449 return mViewer->getIncrementalCompileOperation(); 450 } 451 getObjects()452 MWRender::Objects& RenderingManager::getObjects() 453 { 454 return *mObjects.get(); 455 } 456 getResourceSystem()457 Resource::ResourceSystem* RenderingManager::getResourceSystem() 458 { 459 return mResourceSystem; 460 } 461 getWorkQueue()462 SceneUtil::WorkQueue* RenderingManager::getWorkQueue() 463 { 464 return mWorkQueue.get(); 465 } 466 getUnrefQueue()467 SceneUtil::UnrefQueue* RenderingManager::getUnrefQueue() 468 { 469 return mUnrefQueue.get(); 470 } 471 getTerrain()472 Terrain::World* RenderingManager::getTerrain() 473 { 474 return mTerrain.get(); 475 } 476 preloadCommonAssets()477 void RenderingManager::preloadCommonAssets() 478 { 479 osg::ref_ptr<PreloadCommonAssetsWorkItem> workItem (new PreloadCommonAssetsWorkItem(mResourceSystem)); 480 mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures); 481 mWater->listAssetsToPreload(workItem->mTextures); 482 483 workItem->mModels.push_back(Settings::Manager::getString("xbaseanim", "Models")); 484 workItem->mModels.push_back(Settings::Manager::getString("xbaseanim1st", "Models")); 485 workItem->mModels.push_back(Settings::Manager::getString("xbaseanimfemale", "Models")); 486 workItem->mModels.push_back(Settings::Manager::getString("xargonianswimkna", "Models")); 487 488 workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimkf", "Models")); 489 workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanim1stkf", "Models")); 490 workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimfemalekf", "Models")); 491 workItem->mKeyframes.push_back(Settings::Manager::getString("xargonianswimknakf", "Models")); 492 493 workItem->mTextures.emplace_back("textures/_land_default.dds"); 494 495 mWorkQueue->addWorkItem(workItem); 496 } 497 getReferenceTime() const498 double RenderingManager::getReferenceTime() const 499 { 500 return mViewer->getFrameStamp()->getReferenceTime(); 501 } 502 getLightRoot()503 osg::Group* RenderingManager::getLightRoot() 504 { 505 return mSceneRoot.get(); 506 } 507 setNightEyeFactor(float factor)508 void RenderingManager::setNightEyeFactor(float factor) 509 { 510 if (factor != mNightEyeFactor) 511 { 512 mNightEyeFactor = factor; 513 updateAmbient(); 514 } 515 } 516 setAmbientColour(const osg::Vec4f & colour)517 void RenderingManager::setAmbientColour(const osg::Vec4f &colour) 518 { 519 mAmbientColor = colour; 520 updateAmbient(); 521 } 522 skySetDate(int day,int month)523 void RenderingManager::skySetDate(int day, int month) 524 { 525 mSky->setDate(day, month); 526 } 527 skyGetMasserPhase() const528 int RenderingManager::skyGetMasserPhase() const 529 { 530 return mSky->getMasserPhase(); 531 } 532 skyGetSecundaPhase() const533 int RenderingManager::skyGetSecundaPhase() const 534 { 535 return mSky->getSecundaPhase(); 536 } 537 skySetMoonColour(bool red)538 void RenderingManager::skySetMoonColour(bool red) 539 { 540 mSky->setMoonColour(red); 541 } 542 configureAmbient(const ESM::Cell * cell)543 void RenderingManager::configureAmbient(const ESM::Cell *cell) 544 { 545 bool needsAdjusting = false; 546 if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP) 547 needsAdjusting = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx); 548 549 auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient); 550 551 if (needsAdjusting) 552 { 553 constexpr float pR = 0.2126; 554 constexpr float pG = 0.7152; 555 constexpr float pB = 0.0722; 556 557 // we already work in linear RGB so no conversions are needed for the luminosity function 558 float relativeLuminance = pR*ambient.r() + pG*ambient.g() + pB*ambient.b(); 559 if (relativeLuminance < mMinimumAmbientLuminance) 560 { 561 // brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data as least we can 562 float targetBrightnessIncreaseFactor = mMinimumAmbientLuminance / relativeLuminance; 563 if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f) 564 ambient = osg::Vec4(mMinimumAmbientLuminance, mMinimumAmbientLuminance, mMinimumAmbientLuminance, ambient.a()); 565 else 566 ambient *= targetBrightnessIncreaseFactor; 567 } 568 } 569 570 setAmbientColour(ambient); 571 572 osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); 573 mSunLight->setDiffuse(diffuse); 574 mSunLight->setSpecular(diffuse); 575 mSunLight->setPosition(osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f)); 576 } 577 setSunColour(const osg::Vec4f & diffuse,const osg::Vec4f & specular)578 void RenderingManager::setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular) 579 { 580 // need to wrap this in a StateUpdater? 581 mSunLight->setDiffuse(diffuse); 582 mSunLight->setSpecular(specular); 583 } 584 setSunDirection(const osg::Vec3f & direction)585 void RenderingManager::setSunDirection(const osg::Vec3f &direction) 586 { 587 osg::Vec3 position = direction * -1; 588 // need to wrap this in a StateUpdater? 589 mSunLight->setPosition(osg::Vec4(position.x(), position.y(), position.z(), 0)); 590 591 mSky->setSunDirection(position); 592 } 593 addCell(const MWWorld::CellStore * store)594 void RenderingManager::addCell(const MWWorld::CellStore *store) 595 { 596 mPathgrid->addCell(store); 597 598 mWater->changeCell(store); 599 600 if (store->getCell()->isExterior()) 601 { 602 mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); 603 if (mGroundcoverWorld) 604 mGroundcoverWorld->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); 605 } 606 } removeCell(const MWWorld::CellStore * store)607 void RenderingManager::removeCell(const MWWorld::CellStore *store) 608 { 609 mPathgrid->removeCell(store); 610 mActorsPaths->removeCell(store); 611 mObjects->removeCell(store); 612 613 if (store->getCell()->isExterior()) 614 { 615 mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); 616 if (mGroundcoverWorld) 617 mGroundcoverWorld->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); 618 } 619 620 mWater->removeCell(store); 621 } 622 enableTerrain(bool enable)623 void RenderingManager::enableTerrain(bool enable) 624 { 625 if (!enable) 626 mWater->setCullCallback(nullptr); 627 mTerrain->enable(enable); 628 if (mGroundcoverWorld) 629 mGroundcoverWorld->enable(enable); 630 } 631 setSkyEnabled(bool enabled)632 void RenderingManager::setSkyEnabled(bool enabled) 633 { 634 mSky->setEnabled(enabled); 635 if (enabled) 636 mShadowManager->enableOutdoorMode(); 637 else 638 mShadowManager->enableIndoorMode(); 639 } 640 toggleBorders()641 bool RenderingManager::toggleBorders() 642 { 643 bool borders = !mTerrain->getBordersVisible(); 644 mTerrain->setBordersVisible(borders); 645 return borders; 646 } 647 toggleRenderMode(RenderMode mode)648 bool RenderingManager::toggleRenderMode(RenderMode mode) 649 { 650 if (mode == Render_CollisionDebug || mode == Render_Pathgrid) 651 return mPathgrid->toggleRenderMode(mode); 652 else if (mode == Render_Wireframe) 653 { 654 bool wireframe = !mStateUpdater->getWireframe(); 655 mStateUpdater->setWireframe(wireframe); 656 return wireframe; 657 } 658 else if (mode == Render_Water) 659 { 660 return mWater->toggle(); 661 } 662 else if (mode == Render_Scene) 663 { 664 unsigned int mask = mViewer->getCamera()->getCullMask(); 665 bool enabled = mask&Mask_Scene; 666 enabled = !enabled; 667 if (enabled) 668 mask |= Mask_Scene; 669 else 670 mask &= ~Mask_Scene; 671 mViewer->getCamera()->setCullMask(mask); 672 return enabled; 673 } 674 else if (mode == Render_NavMesh) 675 { 676 return mNavMesh->toggle(); 677 } 678 else if (mode == Render_ActorsPaths) 679 { 680 return mActorsPaths->toggle(); 681 } 682 else if (mode == Render_RecastMesh) 683 { 684 return mRecastMesh->toggle(); 685 } 686 return false; 687 } 688 configureFog(const ESM::Cell * cell)689 void RenderingManager::configureFog(const ESM::Cell *cell) 690 { 691 mFog->configure(mViewDistance, cell); 692 } 693 configureFog(float fogDepth,float underwaterFog,float dlFactor,float dlOffset,const osg::Vec4f & color)694 void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color) 695 { 696 mFog->configure(mViewDistance, fogDepth, underwaterFog, dlFactor, dlOffset, color); 697 } 698 getSkyManager()699 SkyManager* RenderingManager::getSkyManager() 700 { 701 return mSky.get(); 702 } 703 update(float dt,bool paused)704 void RenderingManager::update(float dt, bool paused) 705 { 706 reportStats(); 707 708 mUnrefQueue->flush(mWorkQueue.get()); 709 710 float rainIntensity = mSky->getPrecipitationAlpha(); 711 mWater->setRainIntensity(rainIntensity); 712 713 if (!paused) 714 { 715 mEffectManager->update(dt); 716 mSky->update(dt); 717 mWater->update(dt); 718 719 if (mGroundcoverUpdater) 720 { 721 const MWWorld::Ptr& player = mPlayerAnimation->getPtr(); 722 osg::Vec3f playerPos(player.getRefData().getPosition().asVec3()); 723 724 float windSpeed = mSky->getBaseWindSpeed(); 725 mGroundcoverUpdater->setWindSpeed(windSpeed); 726 mGroundcoverUpdater->setPlayerPos(playerPos); 727 } 728 } 729 730 updateNavMesh(); 731 updateRecastMesh(); 732 733 if (mViewOverShoulderController) 734 mViewOverShoulderController->update(); 735 mCamera->update(dt, paused); 736 737 osg::Vec3d focal, cameraPos; 738 mCamera->getPosition(focal, cameraPos); 739 mCurrentCameraPos = cameraPos; 740 741 bool isUnderwater = mWater->isUnderwater(cameraPos); 742 mStateUpdater->setFogStart(mFog->getFogStart(isUnderwater)); 743 mStateUpdater->setFogEnd(mFog->getFogEnd(isUnderwater)); 744 setFogColor(mFog->getFogColor(isUnderwater)); 745 } 746 updatePlayerPtr(const MWWorld::Ptr & ptr)747 void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) 748 { 749 if(mPlayerAnimation.get()) 750 { 751 setupPlayer(ptr); 752 mPlayerAnimation->updatePtr(ptr); 753 } 754 mCamera->attachTo(ptr); 755 } 756 removePlayer(const MWWorld::Ptr & player)757 void RenderingManager::removePlayer(const MWWorld::Ptr &player) 758 { 759 mWater->removeEmitter(player); 760 } 761 rotateObject(const MWWorld::Ptr & ptr,const osg::Quat & rot)762 void RenderingManager::rotateObject(const MWWorld::Ptr &ptr, const osg::Quat& rot) 763 { 764 if(ptr == mCamera->getTrackingPtr() && 765 !mCamera->isVanityOrPreviewModeEnabled()) 766 { 767 mCamera->rotateCameraToTrackingPtr(); 768 } 769 770 ptr.getRefData().getBaseNode()->setAttitude(rot); 771 } 772 moveObject(const MWWorld::Ptr & ptr,const osg::Vec3f & pos)773 void RenderingManager::moveObject(const MWWorld::Ptr &ptr, const osg::Vec3f &pos) 774 { 775 ptr.getRefData().getBaseNode()->setPosition(pos); 776 } 777 scaleObject(const MWWorld::Ptr & ptr,const osg::Vec3f & scale)778 void RenderingManager::scaleObject(const MWWorld::Ptr &ptr, const osg::Vec3f &scale) 779 { 780 ptr.getRefData().getBaseNode()->setScale(scale); 781 782 if (ptr == mCamera->getTrackingPtr()) // update height of camera 783 mCamera->processViewChange(); 784 } 785 removeObject(const MWWorld::Ptr & ptr)786 void RenderingManager::removeObject(const MWWorld::Ptr &ptr) 787 { 788 mActorsPaths->remove(ptr); 789 mObjects->removeObject(ptr); 790 mWater->removeEmitter(ptr); 791 } 792 setWaterEnabled(bool enabled)793 void RenderingManager::setWaterEnabled(bool enabled) 794 { 795 mWater->setEnabled(enabled); 796 mSky->setWaterEnabled(enabled); 797 } 798 setWaterHeight(float height)799 void RenderingManager::setWaterHeight(float height) 800 { 801 mWater->setCullCallback(mTerrain->getHeightCullCallback(height, Mask_Water)); 802 mWater->setHeight(height); 803 mSky->setWaterHeight(height); 804 } 805 screenshot(osg::Image * image,int w,int h)806 void RenderingManager::screenshot(osg::Image* image, int w, int h) 807 { 808 mScreenshotManager->screenshot(image, w, h); 809 } 810 screenshot360(osg::Image * image)811 bool RenderingManager::screenshot360(osg::Image* image) 812 { 813 if (mCamera->isVanityOrPreviewModeEnabled()) 814 { 815 Log(Debug::Warning) << "Spherical screenshots are not allowed in preview mode."; 816 return false; 817 } 818 819 unsigned int maskBackup = mPlayerAnimation->getObjectRoot()->getNodeMask(); 820 821 if (mCamera->isFirstPerson()) 822 mPlayerAnimation->getObjectRoot()->setNodeMask(0); 823 824 mScreenshotManager->screenshot360(image); 825 826 mPlayerAnimation->getObjectRoot()->setNodeMask(maskBackup); 827 828 return true; 829 } 830 getScreenBounds(const osg::BoundingBox & worldbb)831 osg::Vec4f RenderingManager::getScreenBounds(const osg::BoundingBox &worldbb) 832 { 833 if (!worldbb.valid()) return osg::Vec4f(); 834 osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); 835 float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; 836 for (int i=0; i<8; ++i) 837 { 838 osg::Vec3f corner = worldbb.corner(i); 839 corner = corner * viewProj; 840 841 float x = (corner.x() + 1.f) * 0.5f; 842 float y = (corner.y() - 1.f) * (-0.5f); 843 844 if (x < min_x) 845 min_x = x; 846 847 if (x > max_x) 848 max_x = x; 849 850 if (y < min_y) 851 min_y = y; 852 853 if (y > max_y) 854 max_y = y; 855 } 856 857 return osg::Vec4f(min_x, min_y, max_x, max_y); 858 } 859 getIntersectionResult(osgUtil::LineSegmentIntersector * intersector)860 RenderingManager::RayResult getIntersectionResult (osgUtil::LineSegmentIntersector* intersector) 861 { 862 RenderingManager::RayResult result; 863 result.mHit = false; 864 result.mHitRefnum.unset(); 865 result.mRatio = 0; 866 if (intersector->containsIntersections()) 867 { 868 result.mHit = true; 869 osgUtil::LineSegmentIntersector::Intersection intersection = intersector->getFirstIntersection(); 870 871 result.mHitPointWorld = intersection.getWorldIntersectPoint(); 872 result.mHitNormalWorld = intersection.getWorldIntersectNormal(); 873 result.mRatio = intersection.ratio; 874 875 PtrHolder* ptrHolder = nullptr; 876 std::vector<RefnumMarker*> refnumMarkers; 877 for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) 878 { 879 osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); 880 if (!userDataContainer) 881 continue; 882 for (unsigned int i=0; i<userDataContainer->getNumUserObjects(); ++i) 883 { 884 if (PtrHolder* p = dynamic_cast<PtrHolder*>(userDataContainer->getUserObject(i))) 885 ptrHolder = p; 886 if (RefnumMarker* r = dynamic_cast<RefnumMarker*>(userDataContainer->getUserObject(i))) 887 refnumMarkers.push_back(r); 888 } 889 } 890 891 if (ptrHolder) 892 result.mHitObject = ptrHolder->mPtr; 893 894 unsigned int vertexCounter = 0; 895 for (unsigned int i=0; i<refnumMarkers.size(); ++i) 896 { 897 unsigned int intersectionIndex = intersection.indexList.empty() ? 0 : intersection.indexList[0]; 898 if (!refnumMarkers[i]->mNumVertices || (intersectionIndex >= vertexCounter && intersectionIndex < vertexCounter + refnumMarkers[i]->mNumVertices)) 899 { 900 result.mHitRefnum = refnumMarkers[i]->mRefnum; 901 break; 902 } 903 vertexCounter += refnumMarkers[i]->mNumVertices; 904 } 905 } 906 907 return result; 908 909 } 910 getIntersectionVisitor(osgUtil::Intersector * intersector,bool ignorePlayer,bool ignoreActors)911 osg::ref_ptr<osgUtil::IntersectionVisitor> RenderingManager::getIntersectionVisitor(osgUtil::Intersector *intersector, bool ignorePlayer, bool ignoreActors) 912 { 913 if (!mIntersectionVisitor) 914 mIntersectionVisitor = new osgUtil::IntersectionVisitor; 915 916 mIntersectionVisitor->setTraversalNumber(mViewer->getFrameStamp()->getFrameNumber()); 917 mIntersectionVisitor->setFrameStamp(mViewer->getFrameStamp()); 918 mIntersectionVisitor->setIntersector(intersector); 919 920 unsigned int mask = ~0u; 921 mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water|Mask_SimpleWater|Mask_Groundcover); 922 if (ignorePlayer) 923 mask &= ~(Mask_Player); 924 if (ignoreActors) 925 mask &= ~(Mask_Actor|Mask_Player); 926 927 mIntersectionVisitor->setTraversalMask(mask); 928 return mIntersectionVisitor; 929 } 930 castRay(const osg::Vec3f & origin,const osg::Vec3f & dest,bool ignorePlayer,bool ignoreActors)931 RenderingManager::RayResult RenderingManager::castRay(const osg::Vec3f& origin, const osg::Vec3f& dest, bool ignorePlayer, bool ignoreActors) 932 { 933 osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::MODEL, 934 origin, dest)); 935 intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); 936 937 mRootNode->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); 938 939 return getIntersectionResult(intersector); 940 } 941 castCameraToViewportRay(const float nX,const float nY,float maxDistance,bool ignorePlayer,bool ignoreActors)942 RenderingManager::RayResult RenderingManager::castCameraToViewportRay(const float nX, const float nY, float maxDistance, bool ignorePlayer, bool ignoreActors) 943 { 944 osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector (new osgUtil::LineSegmentIntersector(osgUtil::LineSegmentIntersector::PROJECTION, 945 nX * 2.f - 1.f, nY * (-2.f) + 1.f)); 946 947 osg::Vec3d dist (0.f, 0.f, -maxDistance); 948 949 dist = dist * mViewer->getCamera()->getProjectionMatrix(); 950 951 osg::Vec3d end = intersector->getEnd(); 952 end.z() = dist.z(); 953 intersector->setEnd(end); 954 intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST); 955 956 mViewer->getCamera()->accept(*getIntersectionVisitor(intersector, ignorePlayer, ignoreActors)); 957 958 return getIntersectionResult(intersector); 959 } 960 updatePtr(const MWWorld::Ptr & old,const MWWorld::Ptr & updated)961 void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) 962 { 963 mObjects->updatePtr(old, updated); 964 mActorsPaths->updatePtr(old, updated); 965 } 966 spawnEffect(const std::string & model,const std::string & texture,const osg::Vec3f & worldPosition,float scale,bool isMagicVFX)967 void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const osg::Vec3f &worldPosition, float scale, bool isMagicVFX) 968 { 969 mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX); 970 } 971 notifyWorldSpaceChanged()972 void RenderingManager::notifyWorldSpaceChanged() 973 { 974 mEffectManager->clear(); 975 mWater->clearRipples(); 976 } 977 clear()978 void RenderingManager::clear() 979 { 980 mSky->setMoonColour(false); 981 982 notifyWorldSpaceChanged(); 983 if (mObjectPaging) 984 mObjectPaging->clear(); 985 } 986 getAnimation(const MWWorld::Ptr & ptr)987 MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) 988 { 989 if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) 990 return mPlayerAnimation.get(); 991 992 return mObjects->getAnimation(ptr); 993 } 994 getAnimation(const MWWorld::ConstPtr & ptr) const995 const MWRender::Animation* RenderingManager::getAnimation(const MWWorld::ConstPtr &ptr) const 996 { 997 if (mPlayerAnimation.get() && ptr == mPlayerAnimation->getPtr()) 998 return mPlayerAnimation.get(); 999 1000 return mObjects->getAnimation(ptr); 1001 } 1002 setupPlayer(const MWWorld::Ptr & player)1003 void RenderingManager::setupPlayer(const MWWorld::Ptr &player) 1004 { 1005 if (!mPlayerNode) 1006 { 1007 mPlayerNode = new SceneUtil::PositionAttitudeTransform; 1008 mPlayerNode->setNodeMask(Mask_Player); 1009 mPlayerNode->setName("Player Root"); 1010 mSceneRoot->addChild(mPlayerNode); 1011 } 1012 1013 mPlayerNode->setUserDataContainer(new osg::DefaultUserDataContainer); 1014 mPlayerNode->getUserDataContainer()->addUserObject(new PtrHolder(player)); 1015 1016 player.getRefData().setBaseNode(mPlayerNode); 1017 1018 mWater->removeEmitter(player); 1019 mWater->addEmitter(player); 1020 } 1021 renderPlayer(const MWWorld::Ptr & player)1022 void RenderingManager::renderPlayer(const MWWorld::Ptr &player) 1023 { 1024 mPlayerAnimation = new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, NpcAnimation::VM_Normal, 1025 mFirstPersonFieldOfView); 1026 1027 mCamera->setAnimation(mPlayerAnimation.get()); 1028 mCamera->attachTo(player); 1029 } 1030 rebuildPtr(const MWWorld::Ptr & ptr)1031 void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) 1032 { 1033 NpcAnimation *anim = nullptr; 1034 if(ptr == mPlayerAnimation->getPtr()) 1035 anim = mPlayerAnimation.get(); 1036 else 1037 anim = dynamic_cast<NpcAnimation*>(mObjects->getAnimation(ptr)); 1038 if(anim) 1039 { 1040 anim->rebuild(); 1041 if(mCamera->getTrackingPtr() == ptr) 1042 { 1043 mCamera->attachTo(ptr); 1044 mCamera->setAnimation(anim); 1045 } 1046 } 1047 } 1048 addWaterRippleEmitter(const MWWorld::Ptr & ptr)1049 void RenderingManager::addWaterRippleEmitter(const MWWorld::Ptr &ptr) 1050 { 1051 mWater->addEmitter(ptr); 1052 } 1053 removeWaterRippleEmitter(const MWWorld::Ptr & ptr)1054 void RenderingManager::removeWaterRippleEmitter(const MWWorld::Ptr &ptr) 1055 { 1056 mWater->removeEmitter(ptr); 1057 } 1058 emitWaterRipple(const osg::Vec3f & pos)1059 void RenderingManager::emitWaterRipple(const osg::Vec3f &pos) 1060 { 1061 mWater->emitRipple(pos); 1062 } 1063 updateProjectionMatrix()1064 void RenderingManager::updateProjectionMatrix() 1065 { 1066 double aspect = mViewer->getCamera()->getViewport()->aspectRatio(); 1067 float fov = mFieldOfView; 1068 if (mFieldOfViewOverridden) 1069 fov = mFieldOfViewOverride; 1070 mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); 1071 1072 mUniformNear->set(mNearClip); 1073 mUniformFar->set(mViewDistance); 1074 1075 // Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear. 1076 // Limit FOV here just for sure, otherwise viewing distance can be too high. 1077 fov = std::min(mFieldOfView, 140.f); 1078 float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f); 1079 mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f)); 1080 1081 if (mGroundcoverWorld) 1082 { 1083 float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); 1084 mGroundcoverWorld->setViewDistance(groundcoverDistance * (distanceMult ? 1.f/distanceMult : 1.f)); 1085 } 1086 } 1087 updateTextureFiltering()1088 void RenderingManager::updateTextureFiltering() 1089 { 1090 mViewer->stopThreading(); 1091 1092 mResourceSystem->getSceneManager()->setFilterSettings( 1093 Settings::Manager::getString("texture mag filter", "General"), 1094 Settings::Manager::getString("texture min filter", "General"), 1095 Settings::Manager::getString("texture mipmap", "General"), 1096 Settings::Manager::getInt("anisotropy", "General") 1097 ); 1098 1099 mTerrain->updateTextureFiltering(); 1100 1101 mViewer->startThreading(); 1102 } 1103 updateAmbient()1104 void RenderingManager::updateAmbient() 1105 { 1106 osg::Vec4f color = mAmbientColor; 1107 1108 if (mNightEyeFactor > 0.f) 1109 color += osg::Vec4f(0.7, 0.7, 0.7, 0.0) * mNightEyeFactor; 1110 1111 mStateUpdater->setAmbientColor(color); 1112 } 1113 setFogColor(const osg::Vec4f & color)1114 void RenderingManager::setFogColor(const osg::Vec4f &color) 1115 { 1116 mViewer->getCamera()->setClearColor(color); 1117 1118 mStateUpdater->setFogColor(color); 1119 } 1120 reportStats() const1121 void RenderingManager::reportStats() const 1122 { 1123 osg::Stats* stats = mViewer->getViewerStats(); 1124 unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); 1125 if (stats->collectStats("resource")) 1126 { 1127 stats->setAttribute(frameNumber, "UnrefQueue", mUnrefQueue->getNumItems()); 1128 1129 mTerrain->reportStats(frameNumber, stats); 1130 } 1131 } 1132 processChangedSettings(const Settings::CategorySettingVector & changed)1133 void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) 1134 { 1135 for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) 1136 { 1137 if (it->first == "Camera" && it->second == "field of view") 1138 { 1139 mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); 1140 updateProjectionMatrix(); 1141 } 1142 else if (it->first == "Camera" && it->second == "viewing distance") 1143 { 1144 mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); 1145 if(!Settings::Manager::getBool("use distant fog", "Fog")) 1146 mStateUpdater->setFogEnd(mViewDistance); 1147 updateProjectionMatrix(); 1148 } 1149 else if (it->first == "General" && (it->second == "texture filter" || 1150 it->second == "texture mipmap" || 1151 it->second == "anisotropy")) 1152 { 1153 updateTextureFiltering(); 1154 } 1155 else if (it->first == "Water") 1156 { 1157 mWater->processChangedSettings(changed); 1158 } 1159 else if (it->first == "Shaders" && it->second == "minimum interior brightness") 1160 { 1161 mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); 1162 if (MWMechanics::getPlayer().isInCell()) 1163 configureAmbient(MWMechanics::getPlayer().getCell()->getCell()); 1164 } 1165 else if (it->first == "Shaders" && (it->second == "light bounds multiplier" || 1166 it->second == "maximum light distance" || 1167 it->second == "light fade start" || 1168 it->second == "max lights")) 1169 { 1170 auto* lightManager = static_cast<SceneUtil::LightManager*>(getLightRoot()); 1171 lightManager->processChangedSettings(changed); 1172 1173 if (it->second == "max lights" && !lightManager->usingFFP()) 1174 { 1175 mViewer->stopThreading(); 1176 1177 lightManager->updateMaxLights(); 1178 1179 auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); 1180 for (const auto& [name, key] : lightManager->getLightDefines()) 1181 defines[name] = key; 1182 mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); 1183 1184 mSceneRoot->removeUpdateCallback(mStateUpdater); 1185 mStateUpdater = new StateUpdater; 1186 mSceneRoot->addUpdateCallback(mStateUpdater); 1187 mStateUpdater->setFogEnd(mViewDistance); 1188 updateAmbient(); 1189 1190 mViewer->startThreading(); 1191 } 1192 } 1193 } 1194 } 1195 getNearClipDistance() const1196 float RenderingManager::getNearClipDistance() const 1197 { 1198 return mNearClip; 1199 } 1200 getTerrainHeightAt(const osg::Vec3f & pos)1201 float RenderingManager::getTerrainHeightAt(const osg::Vec3f &pos) 1202 { 1203 return mTerrain->getHeightAt(pos); 1204 } 1205 overrideFieldOfView(float val)1206 void RenderingManager::overrideFieldOfView(float val) 1207 { 1208 if (mFieldOfViewOverridden != true || mFieldOfViewOverride != val) 1209 { 1210 mFieldOfViewOverridden = true; 1211 mFieldOfViewOverride = val; 1212 updateProjectionMatrix(); 1213 } 1214 } 1215 getHalfExtents(const MWWorld::ConstPtr & object) const1216 osg::Vec3f RenderingManager::getHalfExtents(const MWWorld::ConstPtr& object) const 1217 { 1218 osg::Vec3f halfExtents(0, 0, 0); 1219 std::string modelName = object.getClass().getModel(object); 1220 if (modelName.empty()) 1221 return halfExtents; 1222 1223 osg::ref_ptr<const osg::Node> node = mResourceSystem->getSceneManager()->getTemplate(modelName); 1224 osg::ComputeBoundsVisitor computeBoundsVisitor; 1225 computeBoundsVisitor.setTraversalMask(~(MWRender::Mask_ParticleSystem|MWRender::Mask_Effect)); 1226 const_cast<osg::Node*>(node.get())->accept(computeBoundsVisitor); 1227 osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); 1228 1229 if (bounds.valid()) 1230 { 1231 halfExtents[0] = std::abs(bounds.xMax() - bounds.xMin()) / 2.f; 1232 halfExtents[1] = std::abs(bounds.yMax() - bounds.yMin()) / 2.f; 1233 halfExtents[2] = std::abs(bounds.zMax() - bounds.zMin()) / 2.f; 1234 } 1235 1236 return halfExtents; 1237 } 1238 resetFieldOfView()1239 void RenderingManager::resetFieldOfView() 1240 { 1241 if (mFieldOfViewOverridden == true) 1242 { 1243 mFieldOfViewOverridden = false; 1244 1245 updateProjectionMatrix(); 1246 } 1247 } exportSceneGraph(const MWWorld::Ptr & ptr,const std::string & filename,const std::string & format)1248 void RenderingManager::exportSceneGraph(const MWWorld::Ptr &ptr, const std::string &filename, const std::string &format) 1249 { 1250 osg::Node* node = mViewer->getSceneData(); 1251 if (!ptr.isEmpty()) 1252 node = ptr.getRefData().getBaseNode(); 1253 1254 SceneUtil::writeScene(node, filename, format); 1255 } 1256 getLandManager() const1257 LandManager *RenderingManager::getLandManager() const 1258 { 1259 return mTerrainStorage->getLandManager(); 1260 } 1261 updateActorPath(const MWWorld::ConstPtr & actor,const std::deque<osg::Vec3f> & path,const osg::Vec3f & halfExtents,const osg::Vec3f & start,const osg::Vec3f & end) const1262 void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path, 1263 const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const 1264 { 1265 mActorsPaths->update(actor, path, halfExtents, start, end, mNavigator.getSettings()); 1266 } 1267 removeActorPath(const MWWorld::ConstPtr & actor) const1268 void RenderingManager::removeActorPath(const MWWorld::ConstPtr& actor) const 1269 { 1270 mActorsPaths->remove(actor); 1271 } 1272 setNavMeshNumber(const std::size_t value)1273 void RenderingManager::setNavMeshNumber(const std::size_t value) 1274 { 1275 mNavMeshNumber = value; 1276 } 1277 updateNavMesh()1278 void RenderingManager::updateNavMesh() 1279 { 1280 if (!mNavMesh->isEnabled()) 1281 return; 1282 1283 const auto navMeshes = mNavigator.getNavMeshes(); 1284 1285 auto it = navMeshes.begin(); 1286 for (std::size_t i = 0; it != navMeshes.end() && i < mNavMeshNumber; ++i) 1287 ++it; 1288 if (it == navMeshes.end()) 1289 { 1290 mNavMesh->reset(); 1291 } 1292 else 1293 { 1294 try 1295 { 1296 const auto locked = it->second->lockConst(); 1297 mNavMesh->update(locked->getImpl(), mNavMeshNumber, locked->getGeneration(), 1298 locked->getNavMeshRevision(), mNavigator.getSettings()); 1299 } 1300 catch (const std::exception& e) 1301 { 1302 Log(Debug::Error) << "NavMesh render update exception: " << e.what(); 1303 } 1304 } 1305 } 1306 updateRecastMesh()1307 void RenderingManager::updateRecastMesh() 1308 { 1309 if (!mRecastMesh->isEnabled()) 1310 return; 1311 1312 mRecastMesh->update(mNavigator.getRecastMeshTiles(), mNavigator.getSettings()); 1313 } 1314 setActiveGrid(const osg::Vec4i & grid)1315 void RenderingManager::setActiveGrid(const osg::Vec4i &grid) 1316 { 1317 mTerrain->setActiveGrid(grid); 1318 } pagingEnableObject(int type,const MWWorld::ConstPtr & ptr,bool enabled)1319 bool RenderingManager::pagingEnableObject(int type, const MWWorld::ConstPtr& ptr, bool enabled) 1320 { 1321 if (!ptr.isInCell() || !ptr.getCell()->isExterior() || !mObjectPaging) 1322 return false; 1323 if (mObjectPaging->enableObject(type, ptr.getCellRef().getRefNum(), ptr.getCellRef().getPosition().asVec3(), osg::Vec2i(ptr.getCell()->getCell()->getGridX(), ptr.getCell()->getCell()->getGridY()), enabled)) 1324 { 1325 mTerrain->rebuildViews(); 1326 return true; 1327 } 1328 return false; 1329 } pagingBlacklistObject(int type,const MWWorld::ConstPtr & ptr)1330 void RenderingManager::pagingBlacklistObject(int type, const MWWorld::ConstPtr &ptr) 1331 { 1332 if (!ptr.isInCell() || !ptr.getCell()->isExterior() || !mObjectPaging) 1333 return; 1334 const ESM::RefNum & refnum = ptr.getCellRef().getRefNum(); 1335 if (!refnum.hasContentFile()) return; 1336 if (mObjectPaging->blacklistObject(type, refnum, ptr.getCellRef().getPosition().asVec3(), osg::Vec2i(ptr.getCell()->getCell()->getGridX(), ptr.getCell()->getCell()->getGridY()))) 1337 mTerrain->rebuildViews(); 1338 } pagingUnlockCache()1339 bool RenderingManager::pagingUnlockCache() 1340 { 1341 if (mObjectPaging && mObjectPaging->unlockCache()) 1342 { 1343 mTerrain->rebuildViews(); 1344 return true; 1345 } 1346 return false; 1347 } getPagedRefnums(const osg::Vec4i & activeGrid,std::set<ESM::RefNum> & out)1348 void RenderingManager::getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out) 1349 { 1350 if (mObjectPaging) 1351 mObjectPaging->getPagedRefnums(activeGrid, out); 1352 } 1353 } 1354