diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e10688149..e7ed2d921 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,8 +20,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - actors objects renderingmanager animation -# debugging sky camera npcanimation creatureanimation activatoranimation + actors objects renderingmanager animation sky +# debugging camera npcanimation creatureanimation activatoranimation # renderinginterface localmap occlusionquery water shadows # characterpreview globalmap ripplesimulation refraction # terrainstorage renderconst effectmanager weaponanimation @@ -68,8 +68,8 @@ add_openmw_dir (mwworld cells localscripts customdata inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor - contentloader esmloader actiontrap cellreflist cellref physicssystem -# weather projectilemanager + contentloader esmloader actiontrap cellreflist cellref physicssystem weather +# projectilemanager ) add_openmw_dir (mwclass diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59f9fa692..59504048a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -499,9 +499,17 @@ void OMW::Engine::go() //mViewer.setRealizeOperation(ico); mViewer.realize(); std::cout << "realize took " << timer.time_m() << std::endl; + osg::Timer frameTimer; while (!mViewer.done()) { - MWBase::Environment::get().getWorld()->update(0.f, false); + double dt = frameTimer.time_s(); + frameTimer.setStartTick(); + + // frameRenderingQueued(dt); + MWBase::Environment::get().getWorld()->update(dt, false); + + MWBase::Environment::get().getWorld()->advanceTime( + dt*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); mViewer.frame(/*simulationTime*/); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 44334e444..07328b959 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -41,7 +41,7 @@ public: ~Objects(); /// @param animated Attempt to load separate keyframes from a .kf file matching the model file? - /// @param allowLight If false, no lights will be created, and particles systems will be cleared then frozen. + /// @param allowLight If false, no lights will be created, and particles systems will be removed. void insertModel(const MWWorld::Ptr& ptr, const std::string &model, bool animated=false, bool allowLight=true); void insertNPC(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4e5b33c64..e9a5d302c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -13,11 +13,39 @@ #include +#include + #include +#include "sky.hpp" + namespace MWRender { + class StateUpdater : public SceneUtil::StateSetController + { + public: + virtual void setDefaults(osg::StateSet *stateset) + { + osg::LightModel* lightModel = new osg::LightModel; + stateset->setAttribute(lightModel, osg::StateAttribute::ON); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*) + { + osg::LightModel* lightModel = static_cast(stateset->getAttribute(osg::StateAttribute::LIGHTMODEL)); + lightModel->setAmbientIntensity(mAmbientColor); + } + + void setAmbientColor(osg::Vec4f col) + { + mAmbientColor = col; + } + + private: + osg::Vec4f mAmbientColor; + }; + RenderingManager::RenderingManager(osgViewer::Viewer &viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem) : mViewer(viewer) , mRootNode(rootNode) @@ -30,6 +58,8 @@ namespace MWRender mObjects.reset(new Objects(mResourceSystem, lightRoot)); + mSky.reset(new SkyManager(mRootNode, resourceSystem->getSceneManager())); + mViewer.setLightingMode(osgViewer::View::NO_LIGHT); osg::ref_ptr source = new osg::LightSource; @@ -38,17 +68,30 @@ namespace MWRender mSunLight->setDiffuse(osg::Vec4f(0,0,0,1)); mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); mSunLight->setConstantAttenuation(1.f); - source->setStateSetModes(*rootNode->getOrCreateStateSet(), osg::StateAttribute::ON); lightRoot->addChild(source); - rootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); - rootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + + source->setStateSetModes(*mRootNode->getOrCreateStateSet(), osg::StateAttribute::ON); + + mStateUpdater = new StateUpdater; + mRootNode->addUpdateCallback(mStateUpdater); // for consistent benchmarks against the ogre branch. remove later osg::CullStack::CullingMode cullingMode = viewer.getCamera()->getCullingMode(); cullingMode &= ~(osg::CullStack::SMALL_FEATURE_CULLING); viewer.getCamera()->setCullingMode( cullingMode ); + + double fovy, aspect, zNear, zFar; + mViewer.getCamera()->getProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + fovy = 55.f; + mViewer.getCamera()->setProjectionMatrixAsPerspective(fovy, aspect, zNear, zFar); + } + + RenderingManager::~RenderingManager() + { } MWRender::Objects& RenderingManager::getObjects() @@ -66,21 +109,34 @@ namespace MWRender return mResourceSystem; } + void RenderingManager::setAmbientColour(const osg::Vec4f &colour) + { + mStateUpdater->setAmbientColor(colour); + } + void RenderingManager::configureAmbient(const ESM::Cell *cell) { - osg::ref_ptr lightmodel = new osg::LightModel; - lightmodel->setAmbientIntensity(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); + setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); } + void RenderingManager::setSunColour(const osg::Vec4f &colour) + { + mSunLight->setDiffuse(colour); + } + + void RenderingManager::setSunDirection(const osg::Vec3f &direction) + { + mSunLight->setDirection(direction*-1); + + mSky->setSunDirection(direction*-1); + } + osg::Vec3f RenderingManager::getEyePos() { - osg::Vec3d eye; - //mViewer.getCamera()->getViewMatrixAsLookAt(eye, center, up); - eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); + osg::Vec3d eye = mViewer.getCameraManipulator()->getMatrix().getTrans(); return eye; } @@ -89,4 +145,19 @@ namespace MWRender mObjects->removeCell(store); } + void RenderingManager::setSkyEnabled(bool enabled) + { + mSky->setEnabled(enabled); + } + + void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &colour) + { + mViewer.getCamera()->setClearColor(colour); + } + + SkyManager* RenderingManager::getSkyManager() + { + return mSky.get(); + } + } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f0c5040f2..1db0467ef 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -31,20 +31,36 @@ namespace ESM namespace MWRender { + class StateUpdater; + + class SkyManager; + class RenderingManager : public MWRender::RenderingInterface { public: RenderingManager(osgViewer::Viewer& viewer, osg::ref_ptr rootNode, Resource::ResourceSystem* resourceSystem); + ~RenderingManager(); MWRender::Objects& getObjects(); MWRender::Actors& getActors(); Resource::ResourceSystem* getResourceSystem(); + void setAmbientColour(const osg::Vec4f& colour); + + void setSunDirection(const osg::Vec3f& direction); + void setSunColour(const osg::Vec4f& colour); + void configureAmbient(const ESM::Cell* cell); + void configureFog(float fogDepth, const osg::Vec4f& colour); + void removeCell(const MWWorld::CellStore* store); + void setSkyEnabled(bool enabled); + + SkyManager* getSkyManager(); + osg::Vec3f getEyePos(); private: @@ -55,6 +71,12 @@ namespace MWRender osg::ref_ptr mSunLight; std::auto_ptr mObjects; + std::auto_ptr mSky; + + osg::ref_ptr mStateUpdater; + + void operator = (const RenderingManager&); + RenderingManager(const RenderingManager&); }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d591cca2e..be702a221 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1,30 +1,30 @@ #include "sky.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include -#include +#include + +#include #include #include -#include #include -#include +#include +#include + +#include + +#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -34,239 +34,202 @@ #include "renderconst.hpp" #include "renderingmanager.hpp" -using namespace MWRender; -using namespace Ogre; - namespace { -void setAlpha (NifOgre::ObjectScenePtr scene, Ogre::MovableObject* movable, float alpha) -{ - Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(movable); - Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); - while(techs.hasMoreElements()) + osg::StateSet* getWritableStateSet(osg::Node* node) { - Ogre::Technique *tech = techs.getNext(); - Ogre::Technique::PassIterator passes = tech->getPassIterator(); - while(passes.hasMoreElements()) + osg::StateSet* stateset = node->getOrCreateStateSet(); + osg::ref_ptr cloned = static_cast(stateset->clone(osg::CopyOp::SHALLOW_COPY)); + node->setStateSet(cloned); + return cloned; + } + + osg::ref_ptr createAlphaTrackingUnlitMaterial() + { + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::DIFFUSE); + return mat; + } + + osg::ref_ptr createUnlitMaterial() + { + osg::ref_ptr mat = new osg::Material; + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + mat->setColorMode(osg::Material::OFF); + return mat; + } + + osg::ref_ptr createTexturedQuad() + { + osg::ref_ptr geom = new osg::Geometry; + + osg::ref_ptr verts = new osg::Vec3Array; + verts->push_back(osg::Vec3f(-0.5, -0.5, 0)); + verts->push_back(osg::Vec3f(-0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, 0.5, 0)); + verts->push_back(osg::Vec3f(0.5, -0.5, 0)); + + geom->setVertexArray(verts); + + osg::ref_ptr texcoords = new osg::Vec2Array; + texcoords->push_back(osg::Vec2f(0, 0)); + texcoords->push_back(osg::Vec2f(0, 1)); + texcoords->push_back(osg::Vec2f(1, 1)); + texcoords->push_back(osg::Vec2f(1, 0)); + + geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + + geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); + + return geom; + } + +} + +namespace MWRender +{ + +class AtmosphereUpdater : public SceneUtil::StateSetController +{ +public: + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } + +protected: + virtual void setDefaults(osg::StateSet* stateset) + { + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + } + +private: + osg::Vec4f mEmissionColor; +}; + +/// Transform that removes the eyepoint of the modelview matrix, +/// i.e. its children are positioned relative to the camera. +class CameraRelativeTransform : public osg::Transform +{ +public: + CameraRelativeTransform() + { + } + + CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) + : osg::Transform(copy, copyop) + { + } + + META_Node(MWRender, CameraRelativeTransform) + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + { + if (_referenceFrame==RELATIVE_RF) { - Ogre::Pass *pass = passes.getNext(); - Ogre::ColourValue diffuse = pass->getDiffuse(); - diffuse.a = alpha; - pass->setDiffuse(diffuse); + matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); + return false; + } + else // absolute + { + matrix.makeIdentity(); + return true; } } -} - -void setAlpha (NifOgre::ObjectScenePtr scene, float alpha) -{ - for(size_t i = 0; i < scene->mParticles.size(); ++i) - setAlpha(scene, scene->mParticles[i], alpha); - for(size_t i = 0; i < scene->mEntities.size(); ++i) + osg::BoundingSphere computeBound() const { - if (scene->mEntities[i] != scene->mSkelBase) - setAlpha(scene, scene->mEntities[i], alpha); + return osg::BoundingSphere(osg::Vec3f(0,0,0), 0); } -} +}; -} - -BillboardObject::BillboardObject( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) -: mVisibility(1.0f) +class DisableCullingVisitor : public osg::NodeVisitor { - SceneManager* sceneMgr = rootNode->getCreator(); - - Vector3 finalPosition = position.normalisedCopy() * 1000.f; - - static unsigned int bodyCount=0; - - mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); - mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); - - static Ogre::Mesh* plane = MeshManager::getSingleton().createPlane("billboard", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::Plane(Ogre::Vector3(0,0,1), 0), 1, 1, 1, 1, true, 1, 1, 1, Vector3::UNIT_Y).get(); - plane->_setBounds(Ogre::AxisAlignedBox::BOX_INFINITE); - mEntity = sceneMgr->createEntity("billboard"); - mEntity->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); - mEntity->setVisibilityFlags(RV_Sky); - mEntity->setCastShadows(false); - - mNode = rootNode->createChildSceneNode(); - mNode->setPosition(finalPosition); - mNode->attachObject(mEntity); - mNode->setScale(Ogre::Vector3(450.f*initialSize)); - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-position.normalisedCopy())); - - sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); - - bodyCount++; -} - -void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ -} - -void BillboardObject::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) -{ - setVisibility(mVisibility); - setColour(mColour); -} - -void BillboardObject::setVisible(const bool visible) -{ - mEntity->setVisible(visible); -} - -void BillboardObject::setSize(const float size) -{ - mNode->setScale(450.f*size, 450.f*size, 450.f*size); -} - -void BillboardObject::setVisibility(const float visibility) -{ - mVisibility = visibility; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) +public: + DisableCullingVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setDiffuse (0,0,0, visibility); - } -} - -void BillboardObject::setPosition(const Vector3& pPosition) -{ - Vector3 normalised = pPosition.normalisedCopy(); - Vector3 finalPosition = normalised * 1000.f; - mNode->setOrientation(Ogre::Vector3::UNIT_Z.getRotationTo(-normalised)); - mNode->setPosition(finalPosition); -} - -Vector3 BillboardObject::getPosition() const -{ - return mNode->getPosition(); -} - -void BillboardObject::setVisibilityFlags(int flags) -{ - mEntity->setVisibilityFlags(flags); -} - -void BillboardObject::setColour(const ColourValue& pColour) -{ - mColour = pColour; - Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); - for (int i=0; igetNumTechniques(); ++i) - { - Ogre::Technique* t = m->getTechnique(i); - if (t->getNumPasses ()) - t->getPass(0)->setSelfIllumination (pColour); - } -} - -void BillboardObject::setRenderQueue(unsigned int id) -{ - mEntity->setRenderQueueGroup(id); -} - -SceneNode* BillboardObject::getNode() -{ - return mNode; -} - -Moon::Moon( const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode, - const std::string& material) - : BillboardObject(textureName, initialSize, position, rootNode, material) - , mType(Type_Masser) -{ - setVisibility(1.0); - - mMaterial->setProperty("alphatexture", sh::makeProperty(new sh::StringValue(textureName + "_alpha"))); - - mPhase = Moon::Phase_Full; -} - -void Moon::setType(const Moon::Type& type) -{ - mType = type; -} - -void Moon::setPhase(const Moon::Phase& phase) -{ - // Colour texture - Ogre::String textureName = "textures\\tx_"; - - if (mType == Moon::Type_Secunda) textureName += "secunda_"; - else textureName += "masser_"; - - if (phase == Moon::Phase_New) textureName += "new"; - else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; - else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; - else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; - else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; - else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; - else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; - else if (phase == Moon::Phase_Full) textureName += "full"; - - textureName += ".dds"; - - if (mType == Moon::Type_Secunda) - { - sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("secunda_texture_alpha", "textures\\tx_mooncircle_full_s.dds"); - } - else - { - sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); - sh::Factory::getInstance ().setTextureAlias ("masser_texture_alpha", "textures\\tx_mooncircle_full_m.dds"); } - mPhase = phase; -} + void apply(osg::Geode &geode) + { + geode.setCullingActive(false); + } +}; -unsigned int Moon::getPhaseInt() const +class ModVertexAlphaVisitor : public osg::NodeVisitor { - if (mPhase == Moon::Phase_New) return 0; - else if (mPhase == Moon::Phase_WaxingCrescent) return 1; - else if (mPhase == Moon::Phase_WaningCrescent) return 1; - else if (mPhase == Moon::Phase_WaxingHalf) return 2; - else if (mPhase == Moon::Phase_WaningHalf) return 2; - else if (mPhase == Moon::Phase_WaxingGibbous) return 3; - else if (mPhase == Moon::Phase_WaningGibbous) return 3; - else if (mPhase == Moon::Phase_Full) return 4; +public: + ModVertexAlphaVisitor(int meshType) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mMeshType(meshType) + { + } - return 0; -} + void apply(osg::Geode &geode) + { + for (unsigned int i=0; iasGeometry(); + if (!geom) + continue; + + // might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha + // (that isn't possible now, with the diffuse tracking the vertex colors) + + osg::ref_ptr colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements()); + for (unsigned int i=0; isize(); ++i) + { + float alpha = 1.f; + if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (mMeshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 0.25098; // second row + else alpha = 1.f; + } + else if (mMeshType == 2) + { + osg::Vec4Array* origColors = static_cast(geom->getColorArray()); + alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f; + } + + (*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha); + } + + geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX); + } + } + +private: + int mMeshType; +}; + +SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : mSceneManager(sceneManager) + , mHour(0.0f) , mDay(0) , mMonth(0) - , mSun(NULL) - , mSunGlare(NULL) - , mMasser(NULL) - , mSecunda(NULL) - , mCamera(pCamera) - , mRootNode(NULL) - , mSceneMgr(NULL) - , mAtmosphereDay(NULL) - , mAtmosphereNight(NULL) - , mCloudNode(NULL) , mClouds() , mNextClouds() , mCloudBlendFactor(0.0f) , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) - , mLightning(NULL) , mRemainingTransitionTime(0.0f) , mGlareFade(0.0f) , mGlare(0.0f) @@ -277,7 +240,6 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mCreated(false) , mCloudAnimationTimer(0.f) , mMoonRed(false) - , mParticleNode(NULL) , mRainEnabled(false) , mRainTimer(0) , mRainSpeed(0) @@ -285,118 +247,63 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera) , mStormDirection(0,-1,0) , mIsStorm(false) { - mSceneMgr = root->getCreator(); - mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + osg::ref_ptr skyroot (new CameraRelativeTransform); + skyroot->setCullingActive(false); + parentNode->addChild(skyroot); + + mRootNode = skyroot; + + // By default render before the world is rendered + mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin"); } void SkyManager::create() { assert(!mCreated); - sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(1))); - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(1,1,1))); - sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + ModVertexAlphaVisitor modAtmosphere(0); + mAtmosphereDay->accept(modAtmosphere); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); + // osg::Node* alphaBlendedRoot = - // Create light used for thunderstorm - mLightning = mSceneMgr->createLight(); - mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); - mLightning->setVisible (false); - mLightning->setDiffuseColour (ColourValue(3,3,3)); + mAtmosphereUpdater = new AtmosphereUpdater; + mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mSecunda->setType(Moon::Type_Secunda); - mSecunda->setRenderQueue(RQG_SkiesEarly+4); - - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); - mMasser->setRenderQueue(RQG_SkiesEarly+3); - mMasser->setType(Moon::Type_Masser); - - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); - mSunGlare->setRenderQueue(RQG_SkiesLate); - mSunGlare->setVisibilityFlags(RV_NoReflection); - - Ogre::AxisAlignedBox aabInf = Ogre::AxisAlignedBox::BOX_INFINITE; - - // Stars - mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::ObjectScenePtr objects; - if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("meshes\\sky_night_02.nif")) - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_02.nif"); + if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode); else - objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode); + mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + ModVertexAlphaVisitor modStars(2); + mAtmosphereNight->accept(modStars); + mAtmosphereNight->setNodeMask(0); - for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) - { - Entity* night1_ent = objects->mEntities[i]; - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - night1_ent->getMesh()->_setBounds (aabInf); + osg::Geode* geode = new osg::Geode; + osg::ref_ptr sun = createTexturedQuad(); + geode->addDrawable(sun); + osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; + trans->setScale(osg::Vec3f(450,450,450)); + trans->addChild(geode); + mRootNode->addChild(trans); - for (unsigned int j=0; jgetNumSubEntities(); ++j) - { - std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); - sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); + mSunTransform = trans; - std::string textureName = sh::retrieveValue( - sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); + mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); + ModVertexAlphaVisitor modClouds(1); + mCloudNode->accept(modClouds); - m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + osg::ref_ptr sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON); + trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); - night1_ent->getSubEntity(j)->setMaterialName(matName); - } - } - mObjects.push_back(objects); + mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - // Atmosphere (day) - mAtmosphereDay = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* atmosphere_ent = objects->mEntities[i]; - atmosphere_ent->setCastShadows(false); - atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); - atmosphere_ent->setVisibilityFlags(RV_Sky); - - for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) - atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); - - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - atmosphere_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); - - // Clouds - mCloudNode = mRootNode->createChildSceneNode(); - objects = NifOgre::Loader::createObjects(mCloudNode, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < objects->mEntities.size();i++) - { - Entity* clouds_ent = objects->mEntities[i]; - clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) - clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); - clouds_ent->setCastShadows(false); - // Using infinite AAB here to prevent being clipped by the custom near clip plane used for reflections/refractions - clouds_ent->getMesh()->_setBounds (aabInf); - } - mObjects.push_back(objects); + osg::ref_ptr depth = new osg::Depth; + depth->setWriteMask(false); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mCreated = true; } @@ -404,158 +311,51 @@ void SkyManager::create() SkyManager::~SkyManager() { clearRain(); - delete mSun; - delete mSunGlare; - delete mMasser; - delete mSecunda; } int SkyManager::getMasserPhase() const { + return 0; if (!mCreated) return 0; - return mMasser->getPhaseInt(); + //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { + return 0; if (!mCreated) return 0; - return mSecunda->getPhaseInt(); + //return mSecunda->getPhaseInt(); } void SkyManager::clearRain() { - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } } void SkyManager::updateRain(float dt) { - // Move existing rain - // Note: if rain gets disabled, we let the existing rain drops finish falling down. - float minHeight = 200; - for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end();) - { - Ogre::Vector3 pos = it->first->getPosition(); - pos.z -= mRainSpeed * dt; - it->first->setPosition(pos); - if (pos.z < -minHeight - // Here we might want to add a "splash" effect later - || MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), it->first->_getDerivedPosition())) - { - it->second.setNull(); - mSceneMgr->destroySceneNode(it->first); - mRainModels.erase(it++); - } - else - ++it; - } - - // Spawn new rain - float rainFrequency = mRainFrequency; - if (mRainEnabled) - { - mRainTimer += dt; - if (mRainTimer >= 1.f/rainFrequency) - { - mRainTimer = 0; - - // TODO: handle rain settings from Morrowind.ini - const float rangeRandom = 100; - float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); - - // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still - // consider the orientation of the parent node for its position, just not for its orientation - float startHeight = 700; - Ogre::Vector3 worldPos = mParticleNode->_getDerivedPosition(); - worldPos += Ogre::Vector3(xOffs, yOffs, startHeight); - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), worldPos)) - return; - - Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight)); - - // Spawn a new rain object for each instance. - // TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions - // about the rain meshes being Quads and their dimensions. - // Or we could clone meshes into one vertex buffer manually. - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect); - for (unsigned int i=0; imEntities.size(); ++i) - { - objects->mEntities[i]->setRenderQueueGroup(RQG_Alpha); - objects->mEntities[i]->setVisibilityFlags(RV_Sky); - } - for (unsigned int i=0; imParticles.size(); ++i) - { - objects->mParticles[i]->setRenderQueueGroup(RQG_Alpha); - objects->mParticles[i]->setVisibilityFlags(RV_Sky); - } - mRainModels[offsetNode] = objects; - } - } } void SkyManager::update(float duration) { if (!mEnabled) return; - const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + //const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - if (!mParticle.isNull()) - { - for (unsigned int i=0; imControllers.size(); ++i) - mParticle->mControllers[i].update(); - - for (unsigned int i=0; imParticles.size(); ++i) - { - Ogre::ParticleSystem* psys = mParticle->mParticles[i]; - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) - { - Ogre::Particle *p = pi.getNext(); - #if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) - Ogre::Vector3 pos = p->mPosition; - Ogre::Real& timeToLive = p->mTimeToLive; - #else - Ogre::Vector3 pos = p->position; - Ogre::Real& timeToLive = p->timeToLive; - #endif - - if (psys->getKeepParticlesInLocalSpace() && psys->getParentNode()) - pos = psys->getParentNode()->convertLocalToWorldPosition(pos); - - if (MWBase::Environment::get().getWorld()->isUnderwater( - MWBase::Environment::get().getWorld()->getPlayerPtr().getCell(), pos)) - timeToLive = 0; - } - } - - if (mIsStorm) - mParticleNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - } - - if (mIsStorm) - mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); - else - mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); + //if (mIsStorm) + // mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection)); + //else + // mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY); updateRain(duration); // UV Scroll the clouds mCloudAnimationTimer += duration * mCloudSpeed; - sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", - sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this - mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + //mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); + //mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); - mMasser->setColour (ColourValue(1,1,1,1)); + //mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); + //mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { @@ -573,45 +373,36 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun + /* Vector3 sun = mSunGlare->getPosition(); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); val = (val*val*val*val)*6; mSunGlare->setSize(val * mGlareFade); + */ } - mSunGlare->setVisible(mSunEnabled); - mSun->setVisible(mSunEnabled); - mMasser->setVisible(mMasserEnabled); - mSecunda->setVisible(mSecundaEnabled); + //mSunGlare->setVisible(mSunEnabled); + //mSun->setVisible(mSunEnabled); + //mMasser->setVisible(mMasserEnabled); + //mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days - mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); + //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); } -void SkyManager::enable() +void SkyManager::setEnabled(bool enabled) { - if (!mCreated) + if (enabled && !mCreated) create(); - if (mParticleNode) - mParticleNode->setVisible(true); + if (!enabled) + clearRain(); - mRootNode->setVisible(true); - mEnabled = true; -} + mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0); -void SkyManager::disable() -{ - if (mParticleNode) - mParticleNode->setVisible(false); - - clearRain(); - - mRootNode->setVisible(false); - - mEnabled = false; + mEnabled = enabled; } void SkyManager::setMoonColour (bool red) @@ -635,59 +426,53 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCurrentParticleEffect.empty()) { - mParticle.setNull(); + if (mParticleEffect) + mRootNode->removeChild(mParticleEffect); + mParticleEffect = NULL; } else { - mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect); - for(size_t i = 0; i < mParticle->mParticles.size(); ++i) - { - ParticleSystem* particle = mParticle->mParticles[i]; - particle->setRenderQueueGroup(RQG_Alpha); - particle->setVisibilityFlags(RV_Sky); - } + mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode); + DisableCullingVisitor visitor; + mParticleEffect->accept(visitor); + + /* for (size_t i = 0; i < mParticle->mControllers.size(); ++i) { if (mParticle->mControllers[i].getSource().isNull()) mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); } + */ } } if (mClouds != weather.mCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", Misc::ResourceHelpers::correctTexturePath(weather.mCloudTexture)); mClouds = weather.mCloudTexture; } if (mNextClouds != weather.mNextCloudTexture) { - sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", Misc::ResourceHelpers::correctTexturePath(weather.mNextCloudTexture)); mNextClouds = weather.mNextCloudTexture; } if (mCloudBlendFactor != weather.mCloudBlendFactor) { mCloudBlendFactor = weather.mCloudBlendFactor; - sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", - sh::makeProperty(new sh::FloatValue(weather.mCloudBlendFactor))); } if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; - sh::Factory::getInstance().setSharedParameter ("cloudOpacity", - sh::makeProperty(new sh::FloatValue(weather.mCloudOpacity))); } if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, - weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, - weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); - - sh::Factory::getInstance().setSharedParameter ("cloudColour", - sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); + /* + osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f, + weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f, + weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f); + */ mCloudColour = weather.mSunColor; } @@ -695,35 +480,32 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mSkyColour != weather.mSkyColor) { mSkyColour = weather.mSkyColor; - sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4( - weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); + + mAtmosphereUpdater->setEmissionColor(mSkyColour); } if (mFogColour != weather.mFogColor) { mFogColour = weather.mFogColor; - sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( - weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); } mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) { - if (weather.mNightFade == 0) - mAtmosphereNight->setVisible(false); - else + if (weather.mNightFade != 0) { - mAtmosphereNight->setVisible(true); + //sh::Factory::getInstance().setSharedParameter ("nightFade", + // sh::makeProperty(new sh::FloatValue(weather.mNightFade))); - sh::Factory::getInstance().setSharedParameter ("nightFade", - sh::makeProperty(new sh::FloatValue(weather.mNightFade))); - - mStarsOpacity = weather.mNightFade; + //mStarsOpacity = weather.mNightFade; } } + mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + + /* float strength; float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); if (timeofday_angle <= 0.44) @@ -735,12 +517,12 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSun->setVisibility(weather.mGlareView * strength); - mAtmosphereNight->setVisible(weather.mNight && mEnabled); if (mParticle.get()) setAlpha(mParticle, weather.mEffectFade); for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) setAlpha(it->second, weather.mEffectFade); + */ } void SkyManager::setGlare(const float glare) @@ -748,12 +530,6 @@ void SkyManager::setGlare(const float glare) mGlare = glare; } -Vector3 SkyManager::getRealSunPos() -{ - if (!mCreated) return Vector3(0,0,0); - return mSun->getNode()->getPosition() + mCamera->getRealPosition(); -} - void SkyManager::sunEnable() { mSunEnabled = true; @@ -764,32 +540,34 @@ void SkyManager::sunDisable() mSunEnabled = false; } -void SkyManager::setStormDirection(const Vector3 &direction) +void SkyManager::setStormDirection(const Ogre::Vector3 &direction) { mStormDirection = direction; } -void SkyManager::setSunDirection(const Vector3& direction, bool is_night) +void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSun->setPosition(direction); - mSunGlare->setPosition(direction); - float height = direction.z; - float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); + mSunTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mSunTransform->setAttitude(quat); + + //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Vector3& direction) +void SkyManager::setMasserDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mMasser->setPosition(direction); + //mMasser->setPosition(direction); } -void SkyManager::setSecundaDirection(const Vector3& direction) +void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) { if (!mCreated) return; - mSecunda->setPosition(direction); + //mSecunda->setPosition(direction); } void SkyManager::masserEnable() @@ -815,6 +593,7 @@ void SkyManager::secundaDisable() void SkyManager::setLightningStrength(const float factor) { if (!mCreated) return; + /* if (factor > 0.f) { mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); @@ -822,18 +601,19 @@ void SkyManager::setLightningStrength(const float factor) } else mLightning->setVisible(false); + */ } void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - mMasser->setVisibility(fade); + //mMasser->setVisibility(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - mSecunda->setVisibility(fade); + //mSecunda->setVisibility(fade); } void SkyManager::setHour(double hour) @@ -847,28 +627,11 @@ void SkyManager::setDate(int day, int month) mMonth = month; } -Ogre::SceneNode* SkyManager::getSunNode() -{ - if (!mCreated) return 0; - return mSun->getNode(); -} - void SkyManager::setGlareEnabled (bool enabled) { if (!mCreated || !mEnabled) return; - mSunGlare->setVisible (mSunEnabled && enabled); + //mSunGlare->setVisible (mSunEnabled && enabled); } -void SkyManager::attachToNode(SceneNode *sceneNode) -{ - if (!mParticleNode) - { - mParticleNode = sceneNode->createChildSceneNode(); - mParticleNode->setInheritOrientation(false); - } - else - { - sceneNode->addChild(mParticleNode); - } } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 6950dbab3..c8403af71 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,128 +1,35 @@ -#ifndef GAME_RENDER_SKY_H -#define GAME_RENDER_SKY_H - -#include - -#include -#include -#include -#include -#include - -#include - -#include +#ifndef OPENMW_MWRENDER_SKY_H +#define OPENMW_MWRENDER_SKY_H +#include #include "../mwworld/weather.hpp" -namespace Ogre +namespace osg +{ + class Group; + class Node; + class Material; +} + +namespace Resource { - class RenderWindow; - class SceneNode; - class Camera; - class Viewport; class SceneManager; - class Entity; - class BillboardSet; - class TextureUnitState; } namespace MWRender { - class BillboardObject : public sh::MaterialInstanceListener - { - public: - BillboardObject( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); - void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); - - virtual ~BillboardObject() {} - - void setColour(const Ogre::ColourValue& pColour); - void setPosition(const Ogre::Vector3& pPosition); - void setVisible(const bool visible); - void setRenderQueue(unsigned int id); - void setVisibilityFlags(int flags); - void setSize(const float size); - Ogre::Vector3 getPosition() const; - - void setVisibility(const float visibility); - - Ogre::SceneNode* getNode(); - - protected: - float mVisibility; - Ogre::ColourValue mColour; - Ogre::SceneNode* mNode; - sh::MaterialInstance* mMaterial; - Ogre::Entity* mEntity; - }; - - - /* - * The moons need a seperate class because of their shader (which allows them to be partially transparent) - */ - class Moon : public BillboardObject - { - public: - Moon( const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode, - const std::string& material - ); - - virtual ~Moon() {} - - enum Phase - { - Phase_New = 0, - Phase_WaxingCrescent, - Phase_WaxingHalf, - Phase_WaxingGibbous, - Phase_Full, - Phase_WaningGibbous, - Phase_WaningHalf, - Phase_WaningCrescent - }; - - enum Type - { - Type_Masser = 0, - Type_Secunda - }; - - void setPhase(const Phase& phase); - void setType(const Type& type); - - unsigned int getPhaseInt() const; - - private: - Type mType; - Phase mPhase; - }; + class AtmosphereUpdater; class SkyManager { public: - SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); + SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager); ~SkyManager(); - /// Attach weather particle effects to this scene node (should be the Camera's parent node) - void attachToNode(Ogre::SceneNode* sceneNode); - void update(float duration); - void enable(); - - void disable(); + void setEnabled(bool enabled); void setHour (double hour); ///< will be called even when sky is disabled. @@ -143,8 +50,6 @@ namespace MWRender void setWeather(const MWWorld::WeatherResult& weather); - Ogre::SceneNode* getSunNode(); - void sunEnable(); void sunDisable(); @@ -153,7 +58,7 @@ namespace MWRender void setStormDirection(const Ogre::Vector3& direction); - void setSunDirection(const Ogre::Vector3& direction, bool is_night); + void setSunDirection(const osg::Vec3f& direction); void setMasserDirection(const Ogre::Vector3& direction); @@ -173,7 +78,6 @@ namespace MWRender void setGlare(const float glare); void setGlareEnabled(bool enabled); - Ogre::Vector3 getRealSunPos(); private: void create(); @@ -182,6 +86,22 @@ namespace MWRender void updateRain(float dt); void clearRain(); + Resource::SceneManager* mSceneManager; + + osg::ref_ptr mRootNode; + + osg::ref_ptr mParticleEffect; + + osg::ref_ptr mCloudNode; + + osg::ref_ptr mAtmosphereDay; + + osg::ref_ptr mAtmosphereNight; + + osg::ref_ptr mAtmosphereUpdater; + + osg::ref_ptr mSunTransform; + bool mCreated; bool mMoonRed; @@ -194,26 +114,6 @@ namespace MWRender float mCloudAnimationTimer; - BillboardObject* mSun; - BillboardObject* mSunGlare; - Moon* mMasser; - Moon* mSecunda; - - Ogre::Camera* mCamera; - Ogre::SceneNode* mRootNode; - Ogre::SceneManager* mSceneMgr; - - Ogre::SceneNode* mAtmosphereDay; - Ogre::SceneNode* mAtmosphereNight; - - Ogre::SceneNode* mCloudNode; - - std::vector mObjects; - - Ogre::SceneNode* mParticleNode; - NifOgre::ObjectScenePtr mParticle; - - std::map mRainModels; float mRainTimer; Ogre::Vector3 mStormDirection; @@ -225,14 +125,12 @@ namespace MWRender float mCloudOpacity; float mCloudSpeed; float mStarsOpacity; - Ogre::ColourValue mCloudColour; - Ogre::ColourValue mSkyColour; - Ogre::ColourValue mFogColour; + osg::Vec4f mCloudColour; + osg::Vec4f mSkyColour; + osg::Vec4f mFogColour; std::string mCurrentParticleEffect; - Ogre::Light* mLightning; - float mRemainingTransitionTime; float mGlare; // target diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 3a8154ca7..fd6022481 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -1,5 +1,7 @@ #include "fallback.hpp" -#include "boost/lexical_cast.hpp" + +#include + namespace MWWorld { Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) @@ -39,11 +41,11 @@ namespace MWWorld else return boost::lexical_cast(fallback); } - Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + osg::Vec4f Fallback::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); if(sum.empty()) - return Ogre::ColourValue(0,0,0); + return osg::Vec4f(0.f,0.f,0.f,1.f); else { std::string ret[3]; @@ -53,7 +55,7 @@ namespace MWWorld else if (sum[i] != ' ') ret[j]+=sum[i]; } - return Ogre::ColourValue(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + return osg::Vec4f(boost::lexical_cast(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f, 1.f); } } } diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index f69a5e57b..af47063ee 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace MWWorld { @@ -17,7 +17,7 @@ namespace MWWorld float getFallbackFloat(const std::string& fall) const; int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + osg::Vec4f getFallbackColour(const std::string& fall) const; }; } #endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 82814b623..fe4f62953 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -13,16 +13,15 @@ #include "../mwsound/sound.hpp" -//#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/renderingmanager.hpp" +#include "../mwrender/sky.hpp" #include "player.hpp" #include "esmstore.hpp" #include "fallback.hpp" #include "cellstore.hpp" -using namespace Ogre; using namespace MWWorld; -using namespace MWSound; namespace { @@ -31,7 +30,7 @@ namespace return x * (1-factor) + y * factor; } - Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor) + osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } @@ -196,7 +195,7 @@ WeatherManager::~WeatherManager() stopSounds(); } -void WeatherManager::setWeather(const String& weather, bool instant) +void WeatherManager::setWeather(const std::string& weather, bool instant) { if (weather == mCurrentWeather && mNextWeather == "") { @@ -224,7 +223,7 @@ void WeatherManager::setWeather(const String& weather, bool instant) mFirstUpdate = false; } -void WeatherManager::setResult(const String& weatherType) +void WeatherManager::setResult(const std::string& weatherType) { const Weather& current = mWeatherSettings[weatherType]; @@ -387,8 +386,8 @@ void WeatherManager::update(float duration, bool paused) const bool exterior = (world->isCellExterior() || world->isCellQuasiExterior()); if (!exterior) { - mRendering->skyDisable(); - mRendering->getSkyManager()->setLightningStrength(0.f); + mRendering->setSkyEnabled(false); + //mRendering->getSkyManager()->setLightningStrength(0.f); stopSounds(); return; } @@ -421,16 +420,16 @@ void WeatherManager::update(float duration, bool paused) mStormDirection = (playerPos - redMountainPos); mStormDirection.z = 0; - mRendering->getSkyManager()->setStormDirection(mStormDirection); + //mRendering->getSkyManager()->setStormDirection(mStormDirection); } mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); - else - mRendering->getSkyManager()->sunEnable(); + //if (mHour >= mNightStart || mHour <= mSunriseTime) + //mRendering->getSkyManager()->sunDisable(); + //else + //mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -455,11 +454,11 @@ void WeatherManager::update(float duration, bool paused) theta = M_PI * (adjustedHour - adjustedNightStart) / nightDuration; } - Vector3 final( + osg::Vec3f final( static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) static_cast(sin(theta))); - mRendering->setSunDirection( final, is_night ); + mRendering->setSunDirection( final * -1 ); } /* @@ -484,20 +483,20 @@ void WeatherManager::update(float duration, bool paused) if (moonHeight != 0) { int facing = (moonHeight <= 1) ? 1 : -1; - Vector3 masser( + osg::Vec3f masser( (moonHeight - 1) * facing, (1 - moonHeight) * facing, moonHeight); - Vector3 secunda( + osg::Vec3f secunda( (moonHeight - 1) * facing * 1.25f, (1 - moonHeight) * facing * 0.8f, moonHeight); - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); + //mRendering->getSkyManager()->setMasserDirection(masser); + //mRendering->getSkyManager()->setSecundaDirection(secunda); + //mRendering->getSkyManager()->masserEnable(); + //mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -508,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + //mRendering->getSkyManager()->setMasserFade(masserAngleFade); + //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); + //mRendering->getSkyManager()->masserDisable(); + //mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -540,13 +539,13 @@ void WeatherManager::update(float duration, bool paused) } mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - else + //if (mThunderFlash > 0) + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //else { mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; - mRendering->getSkyManager()->setLightningStrength( 0.f ); + //mRendering->getSkyManager()->setLightningStrength( 0.f ); } } else @@ -557,19 +556,19 @@ void WeatherManager::update(float duration, bool paused) { mThunderFlash = mThunderThreshold; - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + //mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); mThunderSoundDelay = 0.25; } } } - else - mRendering->getSkyManager()->setLightningStrength(0.f); + //else + //mRendering->getSkyManager()->setLightningStrength(0.f); } mRendering->setAmbientColour(mResult.mAmbientColor); - mRendering->sunEnable(false); + //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult); @@ -850,3 +849,8 @@ Ogre::Vector3 WeatherManager::getStormDirection() const { return mStormDirection; } + +void WeatherManager::advanceTime(double hours) +{ + mTimePassed += hours*3600; +} diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a2e668159..002f4355c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/soundmanager.hpp" @@ -37,15 +38,15 @@ namespace MWWorld std::string mNextCloudTexture; float mCloudBlendFactor; - Ogre::ColourValue mFogColor; + osg::Vec4f mFogColor; - Ogre::ColourValue mAmbientColor; + osg::Vec4f mAmbientColor; - Ogre::ColourValue mSkyColor; + osg::Vec4f mSkyColor; - Ogre::ColourValue mSunColor; + osg::Vec4f mSunColor; - Ogre::ColourValue mSunDiscColor; + osg::Vec4f mSunDiscColor; float mFogDepth; @@ -80,25 +81,25 @@ namespace MWWorld std::string mCloudTexture; // Sky (atmosphere) colors - Ogre::ColourValue mSkySunriseColor, + osg::Vec4f mSkySunriseColor, mSkyDayColor, mSkySunsetColor, mSkyNightColor; // Fog colors - Ogre::ColourValue mFogSunriseColor, + osg::Vec4f mFogSunriseColor, mFogDayColor, mFogSunsetColor, mFogNightColor; // Ambient lighting colors - Ogre::ColourValue mAmbientSunriseColor, + osg::Vec4f mAmbientSunriseColor, mAmbientDayColor, mAmbientSunsetColor, mAmbientNightColor; // Sun (directional) lighting colors - Ogre::ColourValue mSunSunriseColor, + osg::Vec4f mSunSunriseColor, mSunDayColor, mSunSunsetColor, mSunNightColor; @@ -108,7 +109,7 @@ namespace MWWorld mLandFogNightDepth; // Color modulation for the sun itself during sunset (not completely sure) - Ogre::ColourValue mSunDiscSunsetColor; + osg::Vec4f mSunDiscSunsetColor; // Duration of weather transition (in days) float mTransitionDelta; @@ -185,10 +186,7 @@ namespace MWWorld Ogre::Vector3 getStormDirection() const; - void advanceTime(double hours) - { - mTimePassed += hours*3600; - } + void advanceTime(double hours); unsigned int getWeatherID() const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 994a0c9dd..20298bd85 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -131,18 +131,16 @@ namespace MWWorld void World::adjustSky() { -#if 0 if (mSky && (isCellExterior() || isCellQuasiExterior())) { - mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); - mRendering->skySetDate (mGlobalVariables["day"].getInteger(), - mGlobalVariables["month"].getInteger()); + //mRendering->skySetHour (mGlobalVariables["gamehour"].getFloat()); + //mRendering->skySetDate (mGlobalVariables["day"].getInteger(), + // mGlobalVariables["month"].getInteger()); - mRendering->skyEnable(); + mRendering->setSkyEnabled(true); } else - mRendering->skyDisable(); -#endif + mRendering->setSkyEnabled(false); } World::World ( @@ -171,7 +169,7 @@ namespace MWWorld //mPhysEngine->setSceneManager(renderer.getScene()); - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); mEsm.resize(contentFiles.size()); Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); @@ -267,9 +265,9 @@ namespace MWWorld // mPhysics->toggleCollisionMode(); // we don't want old weather to persist on a new game - //delete mWeatherManager; - //mWeatherManager = 0; - //mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); + delete mWeatherManager; + mWeatherManager = 0; + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); @@ -277,7 +275,7 @@ namespace MWWorld void World::clear() { - //mWeatherManager->clear(); + mWeatherManager->clear(); //mRendering->clear(); #if 0 mProjectileManager->clear(); @@ -348,7 +346,7 @@ namespace MWWorld mCells.write (writer, progress); mGlobalVariables.write (writer, progress); mPlayer->write (writer, progress); - //mWeatherManager->write (writer, progress); + mWeatherManager->write (writer, progress); #if 0 mProjectileManager->write (writer, progress); #endif @@ -378,7 +376,7 @@ namespace MWWorld if (!mStore.readRecord (reader, type) && !mGlobalVariables.readRecord (reader, type) && !mPlayer->readRecord (reader, type) && - //!mWeatherManager->readRecord (reader, type) && + !mWeatherManager->readRecord (reader, type) && !mCells.readRecord (reader, type, contentFileMap) #if 0 && !mProjectileManager->readRecord (reader, type) @@ -479,7 +477,7 @@ namespace MWWorld // Must be cleared before mRendering is destroyed mProjectileManager->clear(); #endif - //delete mWeatherManager; + delete mWeatherManager; delete mWorldScene; delete mRendering; //delete mPhysics; @@ -819,7 +817,7 @@ namespace MWWorld { MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); - //mWeatherManager->advanceTime (hours); + mWeatherManager->advanceTime (hours); hours += mGlobalVariables["gamehour"].getFloat(); @@ -845,7 +843,7 @@ namespace MWWorld //mRendering->skySetHour (hour); - //mWeatherManager->setHour(static_cast(hour)); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1604,11 +1602,11 @@ namespace MWWorld void World::update (float duration, bool paused) { - /* if (mGoToJail && !paused) goToJail(); updateWeather(duration, paused); + /* if (!paused) doPhysics (duration); @@ -1731,17 +1729,17 @@ namespace MWWorld int World::getCurrentWeather() const { - return 0;//mWeatherManager->getWeatherID(); + return mWeatherManager->getWeatherID(); } void World::changeWeather(const std::string& region, const unsigned int id) { - //mWeatherManager->changeWeather(region, id); + mWeatherManager->changeWeather(region, id); } void World::modRegion(const std::string ®ionid, const std::vector &chances) { - //mWeatherManager->modRegion(regionid, chances); + mWeatherManager->modRegion(regionid, chances); } Ogre::Vector2 World::getNorthVector (CellStore* cell) @@ -2975,10 +2973,10 @@ namespace MWWorld if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - //mWeatherManager->switchToNextWeather(true); + mWeatherManager->switchToNextWeather(true); } - //mWeatherManager->update(duration, paused); + mWeatherManager->update(duration, paused); } struct AddDetectedReference diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f77bb4760..9afda480b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -81,7 +81,7 @@ namespace MWWorld MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; - //MWWorld::WeatherManager* mWeatherManager; + MWWorld::WeatherManager* mWeatherManager; MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index abce7020c..6b1c01644 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (resource ) add_component_dir (sceneutil - clone attach lightmanager visitor util + clone attach lightmanager visitor util statesetcontroller ) add_component_dir (nif diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ead6a9669..393f322d7 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -142,4 +142,14 @@ namespace Resource } } + const VFS::Manager* SceneManager::getVFS() const + { + return mVFS; + } + + Resource::TextureManager* SceneManager::getTextureManager() + { + return mTextureManager; + } + } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 4d6ad4855..6a52dfb21 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -55,6 +55,10 @@ namespace Resource /// in cases where multiple contexts are used over the lifetime of the application. void releaseGLObjects(osg::State* state); + const VFS::Manager* getVFS() const; + + Resource::TextureManager* getTextureManager(); + private: const VFS::Manager* mVFS; Resource::TextureManager* mTextureManager; diff --git a/components/sceneutil/statesetcontroller.cpp b/components/sceneutil/statesetcontroller.cpp new file mode 100644 index 000000000..301e709e4 --- /dev/null +++ b/components/sceneutil/statesetcontroller.cpp @@ -0,0 +1,31 @@ +#include "statesetcontroller.hpp" + +#include + +namespace SceneUtil +{ + + void StateSetController::operator()(osg::Node* node, osg::NodeVisitor* nv) + { + if (!mStateSets[0]) + { + // first time setup + osg::StateSet* src = node->getOrCreateStateSet(); + for (int i=0; i<2; ++i) // Using SHALLOW_COPY for StateAttributes, if users want to modify it is their responsibility to set a non-shared one first + // This can be done conveniently in user implementations of the setDefaults() method + { + mStateSets[i] = static_cast(osg::clone(src, osg::CopyOp::SHALLOW_COPY)); + setDefaults(mStateSets[i]); + } + } + + // Swap to make the StateSet in [0] writable, [1] is now the StateSet that was queued by the last frame + std::swap(mStateSets[0], mStateSets[1]); + node->setStateSet(mStateSets[0]); + + apply(mStateSets[0], nv); + + traverse(node, nv); + } + +} diff --git a/components/sceneutil/statesetcontroller.hpp b/components/sceneutil/statesetcontroller.hpp new file mode 100644 index 000000000..7c6c7e407 --- /dev/null +++ b/components/sceneutil/statesetcontroller.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H +#define OPENMW_COMPONENTS_SCENEUTIL_STATESETCONTROLLER_H + +#include + +namespace SceneUtil +{ + + /// @brief Implements efficient pre-frame updating of StateSets. + /// @par With a naive update there would be race conditions when the OSG draw thread of the last frame + /// queues up a StateSet that we want to modify for the next frame. To solve this we could set the StateSet to + /// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw + /// traversals run in parallel can yield up to 200% framerates. + /// @par Race conditions are prevented using a "double buffering" scheme - we have two StateSets that take turns, + /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. + /// After a frame is completed the places are swapped. + /// @par Must be set as UpdateCallback on a Node. + class StateSetController : public osg::NodeCallback + { + public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + protected: + /// Apply state - to override in derived classes + /// @note Due to the double buffering approach you *have* to apply all state + /// even if it has not changed since the last frame. + virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) = 0; + + /// Set default state - optionally override in derived classes + /// @par May be used e.g. to allocate StateAttributes. + virtual void setDefaults(osg::StateSet* stateset) {} + + private: + osg::ref_ptr mStateSets[2]; + }; + +} + +#endif