mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 03:40:14 +00:00
Merge remote-tracking branch 'origin/master' into sceneinput
This commit is contained in:
commit
62047b1868
@ -39,8 +39,6 @@ char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
|
|||||||
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
|
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
|
||||||
const std::string& id) const
|
const std::string& id) const
|
||||||
{
|
{
|
||||||
/// \todo invalidate locals cache on change to scripts
|
|
||||||
|
|
||||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||||
|
|
||||||
int index = mData.getScripts().searchId (id2);
|
int index = mData.getScripts().searchId (id2);
|
||||||
@ -120,3 +118,18 @@ void CSMWorld::ScriptContext::clear()
|
|||||||
mIdsUpdated = false;
|
mIdsUpdated = false;
|
||||||
mLocals.clear();
|
mLocals.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSMWorld::ScriptContext::clearLocals (const std::string& script)
|
||||||
|
{
|
||||||
|
std::map<std::string, Compiler::Locals>::iterator iter =
|
||||||
|
mLocals.find (Misc::StringUtils::lowerCase (script));
|
||||||
|
|
||||||
|
if (iter!=mLocals.end())
|
||||||
|
{
|
||||||
|
mLocals.erase (iter);
|
||||||
|
mIdsUpdated = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -46,6 +46,9 @@ namespace CSMWorld
|
|||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
///< Remove all cached data.
|
///< Remove all cached data.
|
||||||
|
|
||||||
|
/// \return Were there any locals that needed clearing?
|
||||||
|
bool clearLocals (const std::string& script);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,10 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent
|
|||||||
|
|
||||||
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
|
||||||
{
|
{
|
||||||
osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans();
|
osg::Vec3d eye, center, up;
|
||||||
|
mView->getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
osg::Vec3d position = eye;
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
|
||||||
stream
|
stream
|
||||||
|
@ -166,7 +166,9 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
|
|||||||
|
|
||||||
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
|
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
|
||||||
{
|
{
|
||||||
osg::Vec3d position = mView->getCamera()->getViewMatrix().getTrans();
|
osg::Vec3d eye, center, up;
|
||||||
|
mView->getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
osg::Vec3d position = eye;
|
||||||
|
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
|
||||||
|
@ -131,6 +131,11 @@ void CSVWorld::ScriptErrorTable::clear()
|
|||||||
setRowCount (0);
|
setRowCount (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CSVWorld::ScriptErrorTable::clearLocals (const std::string& script)
|
||||||
|
{
|
||||||
|
return mContext.clearLocals (script);
|
||||||
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptErrorTable::cellClicked (int row, int column)
|
void CSVWorld::ScriptErrorTable::cellClicked (int row, int column)
|
||||||
{
|
{
|
||||||
if (item (row, 1))
|
if (item (row, 1))
|
||||||
|
@ -44,6 +44,11 @@ namespace CSVWorld
|
|||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/// Clear local variable cache for \a script.
|
||||||
|
///
|
||||||
|
/// \return Were there any locals that needed clearing?
|
||||||
|
bool clearLocals (const std::string& script);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void cellClicked (int row, int column);
|
void cellClicked (int row, int column);
|
||||||
|
@ -89,6 +89,7 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc:
|
|||||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
|
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
|
||||||
|
|
||||||
mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText);
|
mColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_ScriptText);
|
||||||
|
mIdColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||||
mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
mStateColumn = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||||
|
|
||||||
QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString();
|
QString source = mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString();
|
||||||
@ -241,6 +242,15 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
|
|||||||
|
|
||||||
ScriptEdit::ChangeLock lock (*mEditor);
|
ScriptEdit::ChangeLock lock (*mEditor);
|
||||||
|
|
||||||
|
bool updateRequired = false;
|
||||||
|
|
||||||
|
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
|
||||||
|
{
|
||||||
|
std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData();
|
||||||
|
if (mErrors->clearLocals (id))
|
||||||
|
updateRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||||
|
|
||||||
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
|
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
|
||||||
@ -256,13 +266,28 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo
|
|||||||
mEditor->setPlainText (source);
|
mEditor->setPlainText (source);
|
||||||
mEditor->setTextCursor (cursor);
|
mEditor->setTextCursor (cursor);
|
||||||
|
|
||||||
recompile();
|
updateRequired = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateRequired)
|
||||||
|
recompile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end)
|
||||||
{
|
{
|
||||||
|
bool updateRequired = false;
|
||||||
|
|
||||||
|
for (int i=start; i<=end; ++i)
|
||||||
|
{
|
||||||
|
std::string id = mModel->data (mModel->index (i, mIdColumn)).toString().toUtf8().constData();
|
||||||
|
if (mErrors->clearLocals (id))
|
||||||
|
updateRequired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateRequired)
|
||||||
|
recompile();
|
||||||
|
|
||||||
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
|
||||||
|
|
||||||
if (!parent.isValid() && index.row()>=start && index.row()<=end)
|
if (!parent.isValid() && index.row()>=start && index.row()<=end)
|
||||||
|
@ -38,6 +38,7 @@ namespace CSVWorld
|
|||||||
CSMDoc::Document& mDocument;
|
CSMDoc::Document& mDocument;
|
||||||
CSMWorld::IdTable *mModel;
|
CSMWorld::IdTable *mModel;
|
||||||
int mColumn;
|
int mColumn;
|
||||||
|
int mIdColumn;
|
||||||
int mStateColumn;
|
int mStateColumn;
|
||||||
TableBottomBox *mBottom;
|
TableBottomBox *mBottom;
|
||||||
RecordButtonBar *mButtons;
|
RecordButtonBar *mButtons;
|
||||||
|
@ -23,6 +23,7 @@ add_openmw_dir (mwrender
|
|||||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
||||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
||||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
||||||
|
renderbin
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
20
apps/openmw/mwrender/renderbin.hpp
Normal file
20
apps/openmw/mwrender/renderbin.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef OPENMW_MWRENDER_RENDERBIN_H
|
||||||
|
#define OPENMW_MWRENDER_RENDERBIN_H
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Defines the render bin numbers used in the OpenMW scene graph. The bin with the lowest number is rendered first.
|
||||||
|
/// Beware of RenderBin nesting, in most cases you will want to use setNestRenderBins(false).
|
||||||
|
enum RenderBins
|
||||||
|
{
|
||||||
|
RenderBin_Sky = -1,
|
||||||
|
RenderBin_Default = 0,
|
||||||
|
RenderBin_Water = 9,
|
||||||
|
RenderBin_OcclusionQuery = 10,
|
||||||
|
RenderBin_SunGlare = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -11,6 +11,11 @@
|
|||||||
#include <osg/TexEnvCombine>
|
#include <osg/TexEnvCombine>
|
||||||
#include <osg/TexMat>
|
#include <osg/TexMat>
|
||||||
#include <osg/Version>
|
#include <osg/Version>
|
||||||
|
#include <osg/OcclusionQueryNode>
|
||||||
|
#include <osg/ColorMask>
|
||||||
|
#include <osg/MatrixTransform>
|
||||||
|
#include <osg/BlendFunc>
|
||||||
|
#include <osg/AlphaFunc>
|
||||||
|
|
||||||
#include <osgParticle/ParticleSystem>
|
#include <osgParticle/ParticleSystem>
|
||||||
#include <osgParticle/ParticleSystemUpdater>
|
#include <osgParticle/ParticleSystemUpdater>
|
||||||
@ -38,6 +43,7 @@
|
|||||||
#include "../mwworld/fallback.hpp"
|
#include "../mwworld/fallback.hpp"
|
||||||
|
|
||||||
#include "vismask.hpp"
|
#include "vismask.hpp"
|
||||||
|
#include "renderbin.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -359,19 +365,57 @@ class Sun : public CelestialBody
|
|||||||
public:
|
public:
|
||||||
Sun(osg::Group* parentNode, Resource::TextureManager& textureManager)
|
Sun(osg::Group* parentNode, Resource::TextureManager& textureManager)
|
||||||
: CelestialBody(parentNode, 1.0f, 1)
|
: CelestialBody(parentNode, 1.0f, 1)
|
||||||
, mUpdater(new Updater(textureManager))
|
, mUpdater(new Updater)
|
||||||
{
|
{
|
||||||
mGeode->addUpdateCallback(mUpdater);
|
mTransform->addUpdateCallback(mUpdater);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture2D> sunTex = textureManager.getTexture2D("textures/tx_sun_05.dds",
|
||||||
|
osg::Texture::CLAMP,
|
||||||
|
osg::Texture::CLAMP);
|
||||||
|
|
||||||
|
mGeode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Group> queryNode (new osg::Group);
|
||||||
|
// Need to render after the world geometry so we can correctly test for occlusions
|
||||||
|
queryNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_OcclusionQuery, "RenderBin");
|
||||||
|
queryNode->getOrCreateStateSet()->setNestRenderBins(false);
|
||||||
|
// Set up alpha testing on the occlusion testing subgraph, that way we can get the occlusion tested fragments to match the circular shape of the sun
|
||||||
|
osg::ref_ptr<osg::AlphaFunc> alphaFunc (new osg::AlphaFunc);
|
||||||
|
alphaFunc->setFunction(osg::AlphaFunc::GREATER, 0.8);
|
||||||
|
queryNode->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
||||||
|
queryNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON);
|
||||||
|
queryNode->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
mTransform->addChild(queryNode);
|
||||||
|
|
||||||
|
mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true);
|
||||||
|
mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false);
|
||||||
|
|
||||||
|
createSunFlash(textureManager);
|
||||||
|
createSunGlare();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Sun()
|
~Sun()
|
||||||
{
|
{
|
||||||
mGeode->removeUpdateCallback(mUpdater);
|
mTransform->removeUpdateCallback(mUpdater);
|
||||||
|
destroySunFlash();
|
||||||
|
destroySunGlare();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setColor(const osg::Vec4f& color)
|
||||||
|
{
|
||||||
|
mUpdater->mColor.r() = color.r();
|
||||||
|
mUpdater->mColor.g() = color.g();
|
||||||
|
mUpdater->mColor.b() = color.b();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void adjustTransparency(const float ratio)
|
virtual void adjustTransparency(const float ratio)
|
||||||
{
|
{
|
||||||
mUpdater->mColor.a() = ratio;
|
mUpdater->mColor.a() = ratio;
|
||||||
|
if (mSunGlareCallback)
|
||||||
|
mSunGlareCallback->setGlareView(ratio);
|
||||||
|
if (mSunFlashCallback)
|
||||||
|
mSunFlashCallback->setGlareView(ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDirection(const osg::Vec3f& direction)
|
void setDirection(const osg::Vec3f& direction)
|
||||||
@ -384,37 +428,390 @@ public:
|
|||||||
mTransform->setAttitude(quat);
|
mTransform->setAttitude(quat);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
void setGlareTimeOfDayFade(float val)
|
||||||
struct Updater : public SceneUtil::StateSetUpdater
|
|
||||||
{
|
{
|
||||||
Resource::TextureManager& mTextureManager;
|
if (mSunGlareCallback)
|
||||||
|
mSunGlareCallback->setTimeOfDayFade(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels.
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> createOcclusionQueryNode(osg::Group* parent, bool queryVisible)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
|
||||||
|
oqn->setQueriesEnabled(true);
|
||||||
|
|
||||||
|
// Make it fast! A DYNAMIC query geometry means we can't break frame until the flare is rendered (which is rendered after all the other geometry,
|
||||||
|
// so that would be pretty bad). STATIC should be safe, since our node's local bounds are static, thus computeBounds() which modifies the queryGeometry
|
||||||
|
// is only called once.
|
||||||
|
// Note the debug geometry setDebugDisplay(true) is always DYNAMIC and that can't be changed, not a big deal.
|
||||||
|
oqn->getQueryGeometry()->setDataVariance(osg::Object::STATIC);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geode> queryGeode = osg::clone(mGeode.get(), osg::CopyOp::DEEP_COPY_ALL);
|
||||||
|
// Disable writing to the color buffer. We are using this geode for visibility tests only.
|
||||||
|
osg::ref_ptr<osg::ColorMask> colormask (new osg::ColorMask(0, 0, 0, 0));
|
||||||
|
queryGeode->getOrCreateStateSet()->setAttributeAndModes(colormask, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
oqn->addChild(queryGeode);
|
||||||
|
|
||||||
|
// Remove the default OFF|PROTECTED setting for texturing. We *want* to enable texturing for alpha testing purposes
|
||||||
|
oqn->getQueryStateSet()->removeTextureMode(0, GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
// Need to add texture coordinates so that texturing works. A bit ugly, relies on the vertex ordering
|
||||||
|
// used within OcclusionQueryNode.
|
||||||
|
osg::ref_ptr<osg::Vec2Array> texCoordArray (new osg::Vec2Array);
|
||||||
|
for (int i=0; i<8; ++i)
|
||||||
|
{
|
||||||
|
texCoordArray->push_back(osg::Vec2(0,0));
|
||||||
|
texCoordArray->push_back(osg::Vec2(1,0));
|
||||||
|
texCoordArray->push_back(osg::Vec2(0,0));
|
||||||
|
texCoordArray->push_back(osg::Vec2(1,0));
|
||||||
|
texCoordArray->push_back(osg::Vec2(1,1));
|
||||||
|
texCoordArray->push_back(osg::Vec2(0,1));
|
||||||
|
texCoordArray->push_back(osg::Vec2(0,1));
|
||||||
|
texCoordArray->push_back(osg::Vec2(1,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
oqn->getQueryGeometry()->setTexCoordArray(0, texCoordArray, osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
|
if (queryVisible)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
|
||||||
|
depth->setFunction(osg::Depth::LESS);
|
||||||
|
// This is a trick to make fragments written by the query always use the maximum depth value,
|
||||||
|
// without having to retrieve the current far clipping distance.
|
||||||
|
// We want the sun glare to be "infinitely" far away.
|
||||||
|
depth->setZNear(1.0);
|
||||||
|
depth->setZFar(1.0);
|
||||||
|
oqn->getQueryStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oqn->getQueryStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent->addChild(oqn);
|
||||||
|
|
||||||
|
return oqn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSunFlash(Resource::TextureManager& textureManager)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Texture2D> tex = textureManager.getTexture2D("textures/tx_sun_flash_grey_05.dds",
|
||||||
|
osg::Texture::CLAMP,
|
||||||
|
osg::Texture::CLAMP);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> transform (new osg::PositionAttitudeTransform);
|
||||||
|
const float scale = 2.6f;
|
||||||
|
transform->setScale(osg::Vec3f(scale,scale,scale));
|
||||||
|
|
||||||
|
mTransform->addChild(transform);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
|
transform->addChild(geode);
|
||||||
|
|
||||||
|
geode->addDrawable(createTexturedQuad());
|
||||||
|
|
||||||
|
osg::StateSet* stateset = geode->getOrCreateStateSet();
|
||||||
|
|
||||||
|
stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON);
|
||||||
|
stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin");
|
||||||
|
stateset->setNestRenderBins(false);
|
||||||
|
|
||||||
|
mSunFlashNode = transform;
|
||||||
|
|
||||||
|
mSunFlashCallback = new SunFlashCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels);
|
||||||
|
mSunFlashNode->addCullCallback(mSunFlashCallback);
|
||||||
|
}
|
||||||
|
void destroySunFlash()
|
||||||
|
{
|
||||||
|
if (mSunFlashNode)
|
||||||
|
{
|
||||||
|
mSunFlashNode->removeCullCallback(mSunFlashCallback);
|
||||||
|
mSunFlashCallback = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSunGlare()
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Camera> camera (new osg::Camera);
|
||||||
|
camera->setProjectionMatrix(osg::Matrix::identity());
|
||||||
|
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); // add to skyRoot instead?
|
||||||
|
camera->setViewMatrix(osg::Matrix::identity());
|
||||||
|
camera->setClearMask(0);
|
||||||
|
camera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||||
|
camera->setAllowEventFocus(false);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
|
osg::ref_ptr<osg::Geometry> geom = osg::createTexturedQuadGeometry(osg::Vec3f(-1,-1,0), osg::Vec3f(2,0,0), osg::Vec3f(0,2,0));
|
||||||
|
geode->addDrawable(geom);
|
||||||
|
|
||||||
|
camera->addChild(geode);
|
||||||
|
|
||||||
|
osg::StateSet* stateset = geom->getOrCreateStateSet();
|
||||||
|
|
||||||
|
stateset->setRenderBinDetails(RenderBin_SunGlare, "RenderBin");
|
||||||
|
stateset->setNestRenderBins(false);
|
||||||
|
stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
|
||||||
|
// set up additive blending
|
||||||
|
osg::ref_ptr<osg::BlendFunc> blendFunc (new osg::BlendFunc);
|
||||||
|
blendFunc->setSource(osg::BlendFunc::SRC_ALPHA);
|
||||||
|
blendFunc->setDestination(osg::BlendFunc::ONE);
|
||||||
|
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
mSunGlareCallback = new SunGlareCallback(mOcclusionQueryVisiblePixels, mOcclusionQueryTotalPixels, mTransform);
|
||||||
|
mSunGlareNode = camera;
|
||||||
|
|
||||||
|
mSunGlareNode->addCullCallback(mSunGlareCallback);
|
||||||
|
|
||||||
|
mTransform->addChild(camera);
|
||||||
|
}
|
||||||
|
void destroySunGlare()
|
||||||
|
{
|
||||||
|
if (mSunGlareNode)
|
||||||
|
{
|
||||||
|
mSunGlareNode->removeCullCallback(mSunGlareCallback);
|
||||||
|
mSunGlareCallback = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Updater : public SceneUtil::StateSetUpdater
|
||||||
|
{
|
||||||
|
public:
|
||||||
osg::Vec4f mColor;
|
osg::Vec4f mColor;
|
||||||
|
|
||||||
Updater(Resource::TextureManager& textureManager)
|
Updater()
|
||||||
: mTextureManager(textureManager)
|
: mColor(1.f, 1.f, 1.f, 1.f)
|
||||||
, mColor(0.0f, 0.0f, 0.0f, 1.0f)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setDefaults(osg::StateSet* stateset)
|
virtual void setDefaults(osg::StateSet* stateset)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Texture2D> tex = mTextureManager.getTexture2D("textures/tx_sun_05.dds",
|
stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON);
|
||||||
osg::Texture::CLAMP,
|
|
||||||
osg::Texture::CLAMP);
|
|
||||||
|
|
||||||
stateset->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON);
|
|
||||||
stateset->setAttributeAndModes(createUnlitMaterial(),
|
|
||||||
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*)
|
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor*)
|
||||||
{
|
{
|
||||||
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
|
||||||
mat->setDiffuse(osg::Material::FRONT_AND_BACK, mColor);
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mColor.a()));
|
||||||
|
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(mColor.r(), mColor.g(), mColor.b(), 1));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OcclusionCallback : public osg::NodeCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OcclusionCallback(osg::ref_ptr<osg::OcclusionQueryNode> oqnVisible, osg::ref_ptr<osg::OcclusionQueryNode> oqnTotal)
|
||||||
|
: mOcclusionQueryVisiblePixels(oqnVisible)
|
||||||
|
, mOcclusionQueryTotalPixels(oqnTotal)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float getVisibleRatio (osg::Camera* camera)
|
||||||
|
{
|
||||||
|
int visible = mOcclusionQueryVisiblePixels->getQueryGeometry()->getNumPixels(camera);
|
||||||
|
int total = mOcclusionQueryTotalPixels->getQueryGeometry()->getNumPixels(camera);
|
||||||
|
|
||||||
|
float visibleRatio = 0.f;
|
||||||
|
if (total > 0)
|
||||||
|
visibleRatio = static_cast<float>(visible) / static_cast<float>(total);
|
||||||
|
|
||||||
|
float dt = MWBase::Environment::get().getFrameDuration();
|
||||||
|
|
||||||
|
float lastRatio = mLastRatio[osg::observer_ptr<osg::Camera>(camera)];
|
||||||
|
|
||||||
|
float change = dt*10;
|
||||||
|
|
||||||
|
if (visibleRatio > lastRatio)
|
||||||
|
visibleRatio = std::min(visibleRatio, lastRatio + change);
|
||||||
|
else
|
||||||
|
visibleRatio = std::max(visibleRatio, lastRatio - change);
|
||||||
|
|
||||||
|
mLastRatio[osg::observer_ptr<osg::Camera>(camera)] = visibleRatio;
|
||||||
|
|
||||||
|
return visibleRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryVisiblePixels;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryTotalPixels;
|
||||||
|
|
||||||
|
std::map<osg::observer_ptr<osg::Camera>, float> mLastRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// SunFlashCallback handles fading/scaling of a node depending on occlusion query result. Must be attached as a cull callback.
|
||||||
|
class SunFlashCallback : public OcclusionCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SunFlashCallback(osg::ref_ptr<osg::OcclusionQueryNode> oqnVisible, osg::ref_ptr<osg::OcclusionQueryNode> oqnTotal)
|
||||||
|
: OcclusionCallback(oqnVisible, oqnTotal)
|
||||||
|
, mGlareView(1.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
||||||
|
|
||||||
|
float visibleRatio = getVisibleRatio(cv->getCurrentCamera());
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::StateSet> stateset;
|
||||||
|
|
||||||
|
if (visibleRatio > 0.f)
|
||||||
|
{
|
||||||
|
const float fadeThreshold = 0.1;
|
||||||
|
if (visibleRatio < fadeThreshold)
|
||||||
|
{
|
||||||
|
float fade = 1.f - (fadeThreshold - visibleRatio) / fadeThreshold;
|
||||||
|
osg::ref_ptr<osg::Material> mat (createUnlitMaterial());
|
||||||
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade*mGlareView));
|
||||||
|
stateset = new osg::StateSet;
|
||||||
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float threshold = 0.6;
|
||||||
|
visibleRatio = visibleRatio * (1.f - threshold) + threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = visibleRatio;
|
||||||
|
|
||||||
|
if (scale == 0.f)
|
||||||
|
{
|
||||||
|
// no traverse
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::Matrix modelView = *cv->getModelViewMatrix();
|
||||||
|
|
||||||
|
modelView.preMultScale(osg::Vec3f(visibleRatio, visibleRatio, visibleRatio));
|
||||||
|
|
||||||
|
if (stateset)
|
||||||
|
cv->pushStateSet(stateset);
|
||||||
|
|
||||||
|
cv->pushModelViewMatrix(new osg::RefMatrix(modelView), osg::Transform::RELATIVE_RF);
|
||||||
|
|
||||||
|
traverse(node, nv);
|
||||||
|
|
||||||
|
cv->popModelViewMatrix();
|
||||||
|
|
||||||
|
if (stateset)
|
||||||
|
cv->popStateSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGlareView(float value)
|
||||||
|
{
|
||||||
|
mGlareView = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float mGlareView;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// SunGlareCallback controls a full-screen glare effect depending on occlusion query result and the angle between sun and camera.
|
||||||
|
/// Must be attached as a cull callback to the node above the glare node.
|
||||||
|
class SunGlareCallback : public OcclusionCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SunGlareCallback(osg::ref_ptr<osg::OcclusionQueryNode> oqnVisible, osg::ref_ptr<osg::OcclusionQueryNode> oqnTotal,
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> sunTransform)
|
||||||
|
: OcclusionCallback(oqnVisible, oqnTotal)
|
||||||
|
, mSunTransform(sunTransform)
|
||||||
|
, mTimeOfDayFade(1.f)
|
||||||
|
, mGlareView(1.f)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void operator ()(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
|
{
|
||||||
|
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
||||||
|
|
||||||
|
float angleRadians = getAngleToSunInRadians(cv->getCurrentCamera());
|
||||||
|
float visibleRatio = getVisibleRatio(cv->getCurrentCamera());
|
||||||
|
|
||||||
|
const float angleMaxRadians = osg::DegreesToRadians(30.f); // Sun Glare Fader Angle Max
|
||||||
|
|
||||||
|
float value = 1.f - std::min(1.f, angleRadians / angleMaxRadians);
|
||||||
|
|
||||||
|
const float sunGlareFaderMax = 0.5f;
|
||||||
|
float fade = value * sunGlareFaderMax;
|
||||||
|
|
||||||
|
fade *= mTimeOfDayFade * mGlareView * visibleRatio;
|
||||||
|
|
||||||
|
if (fade == 0.f)
|
||||||
|
{
|
||||||
|
// no traverse
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Material> mat (createUnlitMaterial());
|
||||||
|
|
||||||
|
osg::Vec4f sunGlareFaderColor (222/255.f, 95/255.f, 39/255.f, 1);
|
||||||
|
|
||||||
|
// Replicating a design flaw in MW. The color was being set on both ambient and emissive properties, which multiplies the result by two,
|
||||||
|
// then finally gets clamped by the fixed function pipeline. With the default INI settings, only the red component gets clamped,
|
||||||
|
// so the resulting color looks more orange than red.
|
||||||
|
sunGlareFaderColor *= 2;
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
sunGlareFaderColor[i] = std::min(1.f, sunGlareFaderColor[i]);
|
||||||
|
|
||||||
|
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,fade));
|
||||||
|
mat->setEmission(osg::Material::FRONT_AND_BACK, sunGlareFaderColor);
|
||||||
|
|
||||||
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
cv->pushStateSet(stateset);
|
||||||
|
traverse(node, nv);
|
||||||
|
cv->popStateSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimeOfDayFade(float val)
|
||||||
|
{
|
||||||
|
mTimeOfDayFade = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGlareView(float glareView)
|
||||||
|
{
|
||||||
|
mGlareView = glareView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float getAngleToSunInRadians(osg::Camera* camera) const
|
||||||
|
{
|
||||||
|
osg::Vec3d eye, center, up;
|
||||||
|
camera->getViewMatrixAsLookAt(eye, center, up);
|
||||||
|
|
||||||
|
osg::Vec3d forward = center - eye;
|
||||||
|
osg::Vec3d sun = mSunTransform->getPosition();
|
||||||
|
|
||||||
|
forward.normalize();
|
||||||
|
sun.normalize();
|
||||||
|
float angleRadians = std::acos(forward * sun);
|
||||||
|
return angleRadians;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::PositionAttitudeTransform> mSunTransform;
|
||||||
|
float mTimeOfDayFade;
|
||||||
|
float mGlareView;
|
||||||
|
};
|
||||||
|
|
||||||
osg::ref_ptr<Updater> mUpdater;
|
osg::ref_ptr<Updater> mUpdater;
|
||||||
|
osg::ref_ptr<SunFlashCallback> mSunFlashCallback;
|
||||||
|
osg::ref_ptr<osg::Node> mSunFlashNode;
|
||||||
|
osg::ref_ptr<SunGlareCallback> mSunGlareCallback;
|
||||||
|
osg::ref_ptr<osg::Node> mSunGlareNode;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryVisiblePixels;
|
||||||
|
osg::ref_ptr<osg::OcclusionQueryNode> mOcclusionQueryTotalPixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Moon : public CelestialBody
|
class Moon : public CelestialBody
|
||||||
@ -608,8 +1005,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
|
|||||||
, mCloudSpeed(0.0f)
|
, mCloudSpeed(0.0f)
|
||||||
, mStarsOpacity(0.0f)
|
, mStarsOpacity(0.0f)
|
||||||
, mRemainingTransitionTime(0.0f)
|
, mRemainingTransitionTime(0.0f)
|
||||||
, mGlare(0.0f)
|
|
||||||
, mGlareFade(0.0f)
|
|
||||||
, mRainEnabled(false)
|
, mRainEnabled(false)
|
||||||
, mRainSpeed(0)
|
, mRainSpeed(0)
|
||||||
, mRainFrequency(1)
|
, mRainFrequency(1)
|
||||||
@ -624,7 +1019,7 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana
|
|||||||
mRootNode = skyroot;
|
mRootNode = skyroot;
|
||||||
|
|
||||||
// By default render before the world is rendered
|
// By default render before the world is rendered
|
||||||
mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
|
mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::create()
|
void SkyManager::create()
|
||||||
@ -926,32 +1321,6 @@ void SkyManager::update(float duration)
|
|||||||
mCloudUpdater->setAnimationTimer(mCloudAnimationTimer);
|
mCloudUpdater->setAnimationTimer(mCloudAnimationTimer);
|
||||||
mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer);
|
mCloudUpdater2->setAnimationTimer(mCloudAnimationTimer);
|
||||||
|
|
||||||
if (mSunEnabled)
|
|
||||||
{
|
|
||||||
// take 1/10 sec for fading the glare effect from invisible to full
|
|
||||||
if (mGlareFade > mGlare)
|
|
||||||
{
|
|
||||||
mGlareFade -= duration*10;
|
|
||||||
if (mGlareFade < mGlare) mGlareFade = mGlare;
|
|
||||||
}
|
|
||||||
else if (mGlareFade < mGlare)
|
|
||||||
{
|
|
||||||
mGlareFade += duration*10;
|
|
||||||
if (mGlareFade > mGlare) mGlareFade = mGlare;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate the stars by 360 degrees every 4 days
|
// rotate the stars by 360 degrees every 4 days
|
||||||
mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f);
|
mAtmosphereNightRoll += MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*osg::DegreesToRadians(360.f) / (3600*96.f);
|
||||||
if (mAtmosphereNightNode->getNodeMask() != 0)
|
if (mAtmosphereNightNode->getNodeMask() != 0)
|
||||||
@ -1102,7 +1471,9 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||||||
|
|
||||||
mMasser->adjustTransparency(weather.mGlareView);
|
mMasser->adjustTransparency(weather.mGlareView);
|
||||||
mSecunda->adjustTransparency(weather.mGlareView);
|
mSecunda->adjustTransparency(weather.mGlareView);
|
||||||
mSun->adjustTransparency(weather.mGlareView);
|
|
||||||
|
mSun->setColor(weather.mSunDiscColor);
|
||||||
|
mSun->adjustTransparency(weather.mGlareView * weather.mSunDiscColor.a());
|
||||||
|
|
||||||
float nextStarsOpacity = weather.mNightFade * weather.mGlareView;
|
float nextStarsOpacity = weather.mNightFade * weather.mGlareView;
|
||||||
if(weather.mNight && mStarsOpacity != nextStarsOpacity)
|
if(weather.mNight && mStarsOpacity != nextStarsOpacity)
|
||||||
@ -1114,31 +1485,12 @@ void SkyManager::setWeather(const WeatherResult& weather)
|
|||||||
|
|
||||||
mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0);
|
mAtmosphereNightNode->setNodeMask(weather.mNight ? ~0 : 0);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
float strength;
|
|
||||||
float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length());
|
|
||||||
if (timeofday_angle <= 0.44)
|
|
||||||
strength = timeofday_angle/0.44f;
|
|
||||||
else
|
|
||||||
strength = 1.f;
|
|
||||||
|
|
||||||
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
|
|
||||||
|
|
||||||
mSun->setVisibility(weather.mGlareView * strength);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (mRainFader)
|
if (mRainFader)
|
||||||
mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold?
|
mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold?
|
||||||
if (mParticleFader)
|
if (mParticleFader)
|
||||||
mParticleFader->setAlpha(weather.mEffectFade);
|
mParticleFader->setAlpha(weather.mEffectFade);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setGlare(const float glare)
|
|
||||||
{
|
|
||||||
mGlare = glare;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkyManager::sunEnable()
|
void SkyManager::sunEnable()
|
||||||
{
|
{
|
||||||
if (!mCreated) return;
|
if (!mCreated) return;
|
||||||
@ -1163,8 +1515,6 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction)
|
|||||||
if (!mCreated) return;
|
if (!mCreated) return;
|
||||||
|
|
||||||
mSun->setDirection(direction);
|
mSun->setDirection(direction);
|
||||||
|
|
||||||
//mSunGlare->setPosition(direction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setMasserState(const MoonState& state)
|
void SkyManager::setMasserState(const MoonState& state)
|
||||||
@ -1187,11 +1537,9 @@ void SkyManager::setDate(int day, int month)
|
|||||||
mMonth = month;
|
mMonth = month;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyManager::setGlareEnabled (bool enabled)
|
void SkyManager::setGlareTimeOfDayFade(float val)
|
||||||
{
|
{
|
||||||
if (!mCreated || !mEnabled)
|
mSun->setGlareTimeOfDayFade(val);
|
||||||
return;
|
|
||||||
//mSunGlare->setVisible (mSunEnabled && enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,10 @@ namespace MWRender
|
|||||||
|
|
||||||
osg::Vec4f mSkyColor;
|
osg::Vec4f mSkyColor;
|
||||||
|
|
||||||
|
// sun light color
|
||||||
osg::Vec4f mSunColor;
|
osg::Vec4f mSunColor;
|
||||||
|
|
||||||
|
// alpha is the sun transparency
|
||||||
osg::Vec4f mSunDiscColor;
|
osg::Vec4f mSunDiscColor;
|
||||||
|
|
||||||
float mFogDepth;
|
float mFogDepth;
|
||||||
@ -140,8 +142,7 @@ namespace MWRender
|
|||||||
void setMasserState(const MoonState& state);
|
void setMasserState(const MoonState& state);
|
||||||
void setSecundaState(const MoonState& state);
|
void setSecundaState(const MoonState& state);
|
||||||
|
|
||||||
void setGlare(const float glare);
|
void setGlareTimeOfDayFade(float val);
|
||||||
void setGlareEnabled(bool enabled);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void create();
|
void create();
|
||||||
@ -210,9 +211,6 @@ namespace MWRender
|
|||||||
|
|
||||||
float mRemainingTransitionTime;
|
float mRemainingTransitionTime;
|
||||||
|
|
||||||
float mGlare; // target
|
|
||||||
float mGlareFade; // actual
|
|
||||||
|
|
||||||
bool mRainEnabled;
|
bool mRainEnabled;
|
||||||
std::string mRainEffect;
|
std::string mRainEffect;
|
||||||
float mRainSpeed;
|
float mRainSpeed;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "vismask.hpp"
|
#include "vismask.hpp"
|
||||||
#include "ripplesimulation.hpp"
|
#include "ripplesimulation.hpp"
|
||||||
|
#include "renderbin.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -86,7 +87,7 @@ namespace
|
|||||||
depth->setWriteMask(false);
|
depth->setWriteMask(false);
|
||||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||||
|
|
||||||
stateset->setRenderBinDetails(9, "RenderBin");
|
stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
|
||||||
for (int i=0; i<32; ++i)
|
for (int i=0; i<32; ++i)
|
||||||
|
@ -432,6 +432,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo
|
|||||||
, mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time"))
|
, mSunsetTime(fallback.getFallbackFloat("Weather_Sunset_Time"))
|
||||||
, mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration"))
|
, mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration"))
|
||||||
, mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration"))
|
, mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration"))
|
||||||
|
, mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time"))
|
||||||
, mNightStart(mSunsetTime + mSunsetDuration)
|
, mNightStart(mSunsetTime + mSunsetDuration)
|
||||||
, mNightEnd(mSunriseTime - 0.5f)
|
, mNightEnd(mSunriseTime - 0.5f)
|
||||||
, mDayStart(mSunriseTime + mSunriseDuration)
|
, mDayStart(mSunriseTime + mSunriseDuration)
|
||||||
@ -458,16 +459,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo
|
|||||||
, mPlayingSoundID()
|
, mPlayingSoundID()
|
||||||
{
|
{
|
||||||
mWeatherSettings.reserve(10);
|
mWeatherSettings.reserve(10);
|
||||||
addWeather("Clear", fallback);
|
addWeather("Clear", fallback); // 0
|
||||||
addWeather("Cloudy", fallback);
|
addWeather("Cloudy", fallback); // 1
|
||||||
addWeather("Foggy", fallback);
|
addWeather("Foggy", fallback); // 2
|
||||||
addWeather("Overcast", fallback);
|
addWeather("Overcast", fallback); // 3
|
||||||
addWeather("Rain", fallback, "rain");
|
addWeather("Rain", fallback, "rain"); // 4
|
||||||
addWeather("Thunderstorm", fallback, "rain heavy");
|
addWeather("Thunderstorm", fallback, "rain heavy"); // 5
|
||||||
addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif");
|
addWeather("Ashstorm", fallback, "ashstorm", "meshes\\ashcloud.nif"); // 6
|
||||||
addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif");
|
addWeather("Blight", fallback, "blight", "meshes\\blightcloud.nif"); // 7
|
||||||
addWeather("Snow", fallback, "", "meshes\\snow.nif");
|
addWeather("Snow", fallback, "", "meshes\\snow.nif"); // 8
|
||||||
addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif");
|
addWeather("Blizzard", fallback, "BM Blizzard", "meshes\\blizzard.nif"); // 9
|
||||||
|
|
||||||
Store<ESM::Region>::iterator it = store.get<ESM::Region>().begin();
|
Store<ESM::Region>::iterator it = store.get<ESM::Region>().begin();
|
||||||
for(; it != store.get<ESM::Region>().end(); ++it)
|
for(; it != store.get<ESM::Region>().end(); ++it)
|
||||||
@ -624,6 +625,14 @@ void WeatherManager::update(float duration, bool paused)
|
|||||||
mRendering.setSunDirection( final * -1 );
|
mRendering.setSunDirection( final * -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2;
|
||||||
|
if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime)
|
||||||
|
mRendering.getSkyManager()->setGlareTimeOfDayFade(0);
|
||||||
|
else if (time.getHour() < peakHour)
|
||||||
|
mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (peakHour - time.getHour()) / (peakHour - mSunriseTime));
|
||||||
|
else
|
||||||
|
mRendering.getSkyManager()->setGlareTimeOfDayFade(1 - (time.getHour() - peakHour) / (mSunsetTime - peakHour));
|
||||||
|
|
||||||
mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time));
|
mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time));
|
||||||
mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time));
|
mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time));
|
||||||
|
|
||||||
@ -958,7 +967,6 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
|
|||||||
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
||||||
mResult.mAmbientSoundVolume = 1.f;
|
mResult.mAmbientSoundVolume = 1.f;
|
||||||
mResult.mEffectFade = 1.f;
|
mResult.mEffectFade = 1.f;
|
||||||
mResult.mSunColor = current.mSunDiscSunsetColor;
|
|
||||||
|
|
||||||
mResult.mIsStorm = current.mIsStorm;
|
mResult.mIsStorm = current.mIsStorm;
|
||||||
|
|
||||||
@ -972,6 +980,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
|
|||||||
|
|
||||||
mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth;
|
mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth;
|
||||||
|
|
||||||
|
// TODO: use pre/post sunset/sunrise time values in [Weather] section
|
||||||
// night
|
// night
|
||||||
if (gameHour <= mNightEnd || gameHour >= mNightStart + 1)
|
if (gameHour <= mNightEnd || gameHour >= mNightStart + 1)
|
||||||
{
|
{
|
||||||
@ -1042,6 +1051,36 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
|
|||||||
mResult.mNightFade = factor;
|
mResult.mNightFade = factor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gameHour >= mSunsetTime - mSunPreSunsetTime)
|
||||||
|
{
|
||||||
|
float factor = (gameHour - (mSunsetTime - mSunPreSunsetTime)) / mSunPreSunsetTime;
|
||||||
|
factor = std::min(1.f, factor);
|
||||||
|
mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor);
|
||||||
|
// The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because
|
||||||
|
// MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline
|
||||||
|
// would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped.
|
||||||
|
// Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense.
|
||||||
|
mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor);
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
mResult.mSunDiscColor[i] = std::min(1.f, mResult.mSunDiscColor[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mResult.mSunDiscColor = osg::Vec4f(1,1,1,1);
|
||||||
|
|
||||||
|
if (gameHour >= mSunsetTime)
|
||||||
|
{
|
||||||
|
float fade = std::min(1.f, (gameHour - mSunsetTime) / 2.f);
|
||||||
|
fade = fade*fade;
|
||||||
|
mResult.mSunDiscColor.a() = 1.f - fade;
|
||||||
|
}
|
||||||
|
else if (gameHour >= mSunriseTime && gameHour <= mSunriseTime + 1)
|
||||||
|
{
|
||||||
|
mResult.mSunDiscColor.a() = gameHour - mSunriseTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mResult.mSunDiscColor.a() = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour)
|
inline void WeatherManager::calculateTransitionResult(const float factor, const float gameHour)
|
||||||
|
@ -75,7 +75,7 @@ namespace MWWorld
|
|||||||
float mLandFogDayDepth;
|
float mLandFogDayDepth;
|
||||||
float mLandFogNightDepth;
|
float mLandFogNightDepth;
|
||||||
|
|
||||||
// Color modulation for the sun itself during sunset (not completely sure)
|
// Color modulation for the sun itself during sunset
|
||||||
osg::Vec4f mSunDiscSunsetColor;
|
osg::Vec4f mSunDiscSunsetColor;
|
||||||
|
|
||||||
// Used by scripts to animate signs, etc based on the wind (GetWindSpeed)
|
// Used by scripts to animate signs, etc based on the wind (GetWindSpeed)
|
||||||
@ -242,12 +242,7 @@ namespace MWWorld
|
|||||||
float mSunsetTime;
|
float mSunsetTime;
|
||||||
float mSunriseDuration;
|
float mSunriseDuration;
|
||||||
float mSunsetDuration;
|
float mSunsetDuration;
|
||||||
// Some useful values
|
float mSunPreSunsetTime;
|
||||||
/* TODO: Use pre-sunrise_time, pre-sunset_time,
|
|
||||||
* post-sunrise_time, and post-sunset_time to better
|
|
||||||
* describe sunrise/sunset time.
|
|
||||||
* These values are fallbacks attached to weather.
|
|
||||||
*/
|
|
||||||
float mNightStart;
|
float mNightStart;
|
||||||
float mNightEnd;
|
float mNightEnd;
|
||||||
float mDayStart;
|
float mDayStart;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
|
|
||||||
/// @brief Implements efficient pre-frame updating of StateSets.
|
/// @brief Implements efficient per-frame updating of StateSets.
|
||||||
/// @par With a naive update there would be race conditions when the OSG draw thread of the last frame
|
/// @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
|
/// 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
|
/// DYNAMIC data variance but that would undo all the benefits of the threading model - having the cull and draw
|
||||||
|
Loading…
x
Reference in New Issue
Block a user