mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-05 15:40:10 +00:00
Merge branch 'master' of gitlab.com:openmw/openmw into lua_class_data
This commit is contained in:
commit
ea3eeb6bad
@ -90,6 +90,7 @@
|
||||
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
||||
Bug #7642: Items in repair and recharge menus aren't sorted alphabetically
|
||||
Bug #7647: NPC walk cycle bugs after greeting player
|
||||
Bug #7660: Some inconsistencies regarding Invisibility breaking
|
||||
Feature #3537: Shader-based water ripples
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #6149: Dehardcode Lua API_REVISION
|
||||
|
@ -95,12 +95,16 @@ namespace MWClass
|
||||
|
||||
bool Actor::consume(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) const
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(actor);
|
||||
MWMechanics::CastSpell cast(actor, actor);
|
||||
const ESM::RefId& recordId = consumable.getCellRef().getRefId();
|
||||
MWBase::Environment::get().getWorldModel()->registerPtr(consumable);
|
||||
MWBase::Environment::get().getLuaManager()->itemConsumed(consumable, actor);
|
||||
actor.getClass().getContainerStore(actor).remove(consumable, 1);
|
||||
return cast.cast(recordId);
|
||||
if (cast.cast(recordId))
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(actor);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ namespace MWGui::Formatting
|
||||
: GraphicElement(parent, pag, blockStyle)
|
||||
, mTextStyle(textStyle)
|
||||
{
|
||||
MyGUI::EditBox* box = parent->createWidget<MyGUI::EditBox>("NormalText",
|
||||
Gui::EditBox* box = parent->createWidget<Gui::EditBox>("NormalText",
|
||||
MyGUI::IntCoord(0, pag.getCurrentTop(), pag.getPageWidth(), 0), MyGUI::Align::Left | MyGUI::Align::Top,
|
||||
parent->getName() + MyGUI::utility::toString(parent->getChildCount()));
|
||||
box->setEditStatic(true);
|
||||
|
@ -161,7 +161,7 @@ namespace MWGui
|
||||
private:
|
||||
int currentFontHeight() const;
|
||||
TextStyle mTextStyle;
|
||||
MyGUI::EditBox* mEditBox;
|
||||
Gui::EditBox* mEditBox;
|
||||
};
|
||||
|
||||
class ImageElement : public GraphicElement
|
||||
|
@ -238,7 +238,7 @@ namespace MWGui
|
||||
mLines.emplace_back(separator, (MyGUI::Widget*)nullptr, NoSpellIndex);
|
||||
}
|
||||
|
||||
MyGUI::TextBox* groupWidget = mScrollView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||
MyGUI::TextBox* groupWidget = mScrollView->createWidget<Gui::TextBox>("SandBrightText",
|
||||
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
groupWidget->setCaptionWithReplacing(label);
|
||||
groupWidget->setTextAlign(MyGUI::Align::Left);
|
||||
@ -246,7 +246,7 @@ namespace MWGui
|
||||
|
||||
if (!label2.empty())
|
||||
{
|
||||
MyGUI::TextBox* groupWidget2 = mScrollView->createWidget<MyGUI::TextBox>("SandBrightText",
|
||||
MyGUI::TextBox* groupWidget2 = mScrollView->createWidget<Gui::TextBox>("SandBrightText",
|
||||
MyGUI::IntCoord(0, 0, mScrollView->getWidth(), 24), MyGUI::Align::Left | MyGUI::Align::Top);
|
||||
groupWidget2->setCaptionWithReplacing(label2);
|
||||
groupWidget2->setTextAlign(MyGUI::Align::Right);
|
||||
|
@ -443,7 +443,7 @@ namespace MWGui
|
||||
const std::string realImage
|
||||
= Misc::ResourceHelpers::correctIconPath(image, MWBase::Environment::get().getResourceSystem()->getVFS());
|
||||
|
||||
MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget<MyGUI::EditBox>(
|
||||
Gui::EditBox* captionWidget = mDynamicToolTipBox->createWidget<Gui::EditBox>(
|
||||
"NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption");
|
||||
captionWidget->setEditStatic(true);
|
||||
captionWidget->setNeedKeyFocus(false);
|
||||
@ -452,7 +452,7 @@ namespace MWGui
|
||||
|
||||
int captionHeight = std::max(!caption.empty() ? captionSize.height : 0, imageSize);
|
||||
|
||||
MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget<MyGUI::EditBox>("SandText",
|
||||
Gui::EditBox* textWidget = mDynamicToolTipBox->createWidget<Gui::EditBox>("SandText",
|
||||
MyGUI::IntCoord(0, captionHeight + imageCaptionVPadding, 300, 300 - captionHeight - imageCaptionVPadding),
|
||||
MyGUI::Align::Stretch, "ToolTipText");
|
||||
textWidget->setEditStatic(true);
|
||||
@ -474,7 +474,7 @@ namespace MWGui
|
||||
MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget<MyGUI::ImageBox>("MarkerButton",
|
||||
MyGUI::IntCoord(padding.left, totalSize.height + padding.top, 8, 8), MyGUI::Align::Default);
|
||||
icon->setColour(MyGUI::Colour(1.0f, 0.3f, 0.3f));
|
||||
MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget<MyGUI::EditBox>("SandText",
|
||||
Gui::EditBox* edit = mDynamicToolTipBox->createWidget<Gui::EditBox>("SandText",
|
||||
MyGUI::IntCoord(padding.left + 8 + 4, totalSize.height + padding.top, 300 - padding.left - 8 - 4,
|
||||
300 - totalSize.height),
|
||||
MyGUI::Align::Default);
|
||||
|
@ -510,6 +510,8 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create(const std::string& nam
|
||||
if (readyStatus != Result_Success)
|
||||
return readyStatus;
|
||||
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(mAlchemist);
|
||||
|
||||
Result result = Result_RandomFailure;
|
||||
int brewedCount = 0;
|
||||
for (int i = 0; i < count; ++i)
|
||||
|
@ -44,6 +44,8 @@ namespace MWMechanics
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(player);
|
||||
|
||||
float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
if (luckTerm < 1 || luckTerm > 10)
|
||||
luckTerm = 1;
|
||||
|
@ -22,6 +22,8 @@ namespace MWMechanics
|
||||
MWWorld::Ptr player = getPlayer();
|
||||
MWWorld::LiveCellRef<ESM::Repair>* ref = mTool.get<ESM::Repair>();
|
||||
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(player);
|
||||
|
||||
// unstack tool if required
|
||||
player.getClass().getContainerStore(player).unstack(mTool);
|
||||
|
||||
|
@ -328,14 +328,12 @@ namespace MWRender
|
||||
{
|
||||
osg::State* state = renderInfo.getState();
|
||||
|
||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
PostProcessor* postProcessor = static_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
|
||||
state->applyAttribute(mDepth);
|
||||
|
||||
unsigned int frameId = state->getFrameStamp()->getFrameNumber() % 2;
|
||||
|
||||
if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId))
|
||||
{
|
||||
postProcessor->getFbo(PostProcessor::FBO_FirstPerson, frameId)->apply(*state);
|
||||
if (mPassNormals)
|
||||
{
|
||||
@ -361,13 +359,6 @@ namespace MWRender
|
||||
|
||||
if (postProcessor->getFbo(PostProcessor::FBO_OpaqueDepth, frameId))
|
||||
primaryFBO->apply(*state);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to standard depth clear when we are not rendering our main scene via an intermediate FBO
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
bin->drawImplementation(renderInfo, previous);
|
||||
}
|
||||
|
||||
state->checkGLErrors("after DepthClearCallback::drawImplementation");
|
||||
}
|
||||
|
@ -43,19 +43,16 @@ namespace MWRender
|
||||
mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0));
|
||||
}
|
||||
|
||||
void PingPongCanvas::setCurrentFrameData(size_t frameId, fx::DispatchArray&& data)
|
||||
void PingPongCanvas::setPasses(fx::DispatchArray&& passes)
|
||||
{
|
||||
mBufferData[frameId].data = std::move(data);
|
||||
mPasses = std::move(passes);
|
||||
}
|
||||
|
||||
void PingPongCanvas::setMask(size_t frameId, bool underwater, bool exterior)
|
||||
void PingPongCanvas::setMask(bool underwater, bool exterior)
|
||||
{
|
||||
mBufferData[frameId].mask = 0;
|
||||
|
||||
mBufferData[frameId].mask
|
||||
|= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
|
||||
mBufferData[frameId].mask
|
||||
|= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
|
||||
mMask = 0;
|
||||
mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
|
||||
mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
|
||||
}
|
||||
|
||||
void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const
|
||||
@ -77,19 +74,15 @@ namespace MWRender
|
||||
|
||||
size_t frameId = state.getFrameStamp()->getFrameNumber() % 2;
|
||||
|
||||
auto& bufferData = mBufferData[frameId];
|
||||
|
||||
const auto& data = bufferData.data;
|
||||
|
||||
std::vector<size_t> filtered;
|
||||
|
||||
filtered.reserve(data.size());
|
||||
filtered.reserve(mPasses.size());
|
||||
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
for (size_t i = 0; i < mPasses.size(); ++i)
|
||||
{
|
||||
const auto& node = data[i];
|
||||
const auto& node = mPasses[i];
|
||||
|
||||
if (bufferData.mask & node.mFlags)
|
||||
if (mMask & node.mFlags)
|
||||
continue;
|
||||
|
||||
filtered.push_back(i);
|
||||
@ -97,7 +90,7 @@ namespace MWRender
|
||||
|
||||
auto* resolveViewport = state.getCurrentViewport();
|
||||
|
||||
if (filtered.empty() || !bufferData.postprocessing)
|
||||
if (filtered.empty() || !mPostprocessing)
|
||||
{
|
||||
state.pushStateSet(mFallbackStateSet);
|
||||
state.apply();
|
||||
@ -108,7 +101,7 @@ namespace MWRender
|
||||
state.apply();
|
||||
}
|
||||
|
||||
state.applyTextureAttribute(0, bufferData.sceneTex);
|
||||
state.applyTextureAttribute(0, mTextureScene);
|
||||
resolveViewport->apply(state);
|
||||
|
||||
drawGeometry(renderInfo);
|
||||
@ -124,13 +117,12 @@ namespace MWRender
|
||||
|
||||
const unsigned int handle = mFbos[0] ? mFbos[0]->getHandle(state.getContextID()) : 0;
|
||||
|
||||
if (handle == 0 || bufferData.dirty)
|
||||
if (handle == 0 || mDirty)
|
||||
{
|
||||
for (auto& fbo : mFbos)
|
||||
{
|
||||
fbo = new osg::FrameBufferObject;
|
||||
attachCloneOfTemplate(
|
||||
fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
||||
attachCloneOfTemplate(fbo, osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||
fbo->apply(state);
|
||||
glClearColor(0.5, 0.5, 0.5, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
@ -140,7 +132,7 @@ namespace MWRender
|
||||
{
|
||||
mMultiviewResolveFramebuffer = new osg::FrameBufferObject();
|
||||
attachCloneOfTemplate(mMultiviewResolveFramebuffer,
|
||||
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, bufferData.sceneTexLDR);
|
||||
osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, mTextureScene);
|
||||
mMultiviewResolveFramebuffer->apply(state);
|
||||
glClearColor(0.5, 0.5, 0.5, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
@ -150,15 +142,15 @@ namespace MWRender
|
||||
.getTexture());
|
||||
}
|
||||
|
||||
mLuminanceCalculator.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
||||
mLuminanceCalculator.dirty(mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||
|
||||
if (Stereo::getStereo())
|
||||
mRenderViewport = new osg::Viewport(
|
||||
0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
|
||||
mRenderViewport
|
||||
= new osg::Viewport(0, 0, mTextureScene->getTextureWidth(), mTextureScene->getTextureHeight());
|
||||
else
|
||||
mRenderViewport = nullptr;
|
||||
|
||||
bufferData.dirty = false;
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
constexpr std::array<std::array<int, 2>, 3> buffers
|
||||
@ -166,7 +158,7 @@ namespace MWRender
|
||||
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT2_EXT },
|
||||
{ GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT } } };
|
||||
|
||||
(bufferData.hdr) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable();
|
||||
(mAvgLum) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable();
|
||||
|
||||
// A histogram based approach is superior way to calculate scene luminance. Using mipmaps is more broadly
|
||||
// supported, so that's what we use for now.
|
||||
@ -181,8 +173,7 @@ namespace MWRender
|
||||
|
||||
const unsigned int cid = state.getContextID();
|
||||
|
||||
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo
|
||||
= bufferData.destination ? bufferData.destination : nullptr;
|
||||
const osg::ref_ptr<osg::FrameBufferObject>& destinationFbo = mDestinationFBO ? mDestinationFBO : nullptr;
|
||||
unsigned int destinationHandle = destinationFbo ? destinationFbo->getHandle(cid) : 0;
|
||||
|
||||
auto bindDestinationFbo = [&]() {
|
||||
@ -206,17 +197,16 @@ namespace MWRender
|
||||
|
||||
for (const size_t& index : filtered)
|
||||
{
|
||||
const auto& node = data[index];
|
||||
const auto& node = mPasses[index];
|
||||
|
||||
node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, bufferData.depthTex);
|
||||
node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, mTextureDepth);
|
||||
|
||||
if (bufferData.hdr)
|
||||
if (mAvgLum)
|
||||
node.mRootStateSet->setTextureAttribute(
|
||||
PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId));
|
||||
|
||||
if (bufferData.normalsTex)
|
||||
node.mRootStateSet->setTextureAttribute(
|
||||
PostProcessor::TextureUnits::Unit_Normals, bufferData.normalsTex);
|
||||
if (mTextureNormals)
|
||||
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, mTextureNormals);
|
||||
|
||||
state.pushStateSet(node.mRootStateSet);
|
||||
state.apply();
|
||||
@ -231,7 +221,7 @@ namespace MWRender
|
||||
|
||||
// VR-TODO: This won't actually work for tex2darrays
|
||||
if (lastShader == 0)
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, bufferData.sceneTex);
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, mTextureScene);
|
||||
else
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastShader,
|
||||
(osg::Texture*)mFbos[lastShader - GL_COLOR_ATTACHMENT0_EXT]
|
||||
@ -239,7 +229,7 @@ namespace MWRender
|
||||
.getTexture());
|
||||
|
||||
if (lastDraw == 0)
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, bufferData.sceneTex);
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass, mTextureScene);
|
||||
else
|
||||
pass.mStateSet->setTextureAttribute(PostProcessor::Unit_LastPass,
|
||||
(osg::Texture*)mFbos[lastDraw - GL_COLOR_ATTACHMENT0_EXT]
|
||||
@ -260,7 +250,6 @@ namespace MWRender
|
||||
}
|
||||
|
||||
lastApplied = pass.mRenderTarget->getHandle(state.getContextID());
|
||||
;
|
||||
}
|
||||
else if (pass.mResolve && index == filtered.back())
|
||||
{
|
||||
|
@ -24,76 +24,52 @@ namespace MWRender
|
||||
public:
|
||||
PingPongCanvas(Shader::ShaderManager& shaderManager);
|
||||
|
||||
void drawImplementation(osg::RenderInfo& renderInfo) const override;
|
||||
|
||||
void dirty(size_t frameId) { mBufferData[frameId].dirty = true; }
|
||||
|
||||
const fx::DispatchArray& getCurrentFrameData(size_t frame) { return mBufferData[frame % 2].data; }
|
||||
|
||||
// Sets current frame pass data and stores copy of dispatch array to apply to next frame data
|
||||
void setCurrentFrameData(size_t frameId, fx::DispatchArray&& data);
|
||||
|
||||
void setMask(size_t frameId, bool underwater, bool exterior);
|
||||
|
||||
void setSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].sceneTex = tex; }
|
||||
|
||||
void setLDRSceneTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex)
|
||||
{
|
||||
mBufferData[frameId].sceneTexLDR = tex;
|
||||
}
|
||||
|
||||
void setDepthTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex) { mBufferData[frameId].depthTex = tex; }
|
||||
|
||||
void setNormalsTexture(size_t frameId, osg::ref_ptr<osg::Texture> tex)
|
||||
{
|
||||
mBufferData[frameId].normalsTex = tex;
|
||||
}
|
||||
|
||||
void setHDR(size_t frameId, bool hdr) { mBufferData[frameId].hdr = hdr; }
|
||||
|
||||
void setPostProcessing(size_t frameId, bool postprocessing)
|
||||
{
|
||||
mBufferData[frameId].postprocessing = postprocessing;
|
||||
}
|
||||
|
||||
const osg::ref_ptr<osg::Texture>& getSceneTexture(size_t frameId) const
|
||||
{
|
||||
return mBufferData[frameId].sceneTex;
|
||||
}
|
||||
|
||||
void drawGeometry(osg::RenderInfo& renderInfo) const;
|
||||
|
||||
private:
|
||||
void copyNewFrameData(size_t frameId) const;
|
||||
void drawImplementation(osg::RenderInfo& renderInfo) const override;
|
||||
|
||||
mutable LuminanceCalculator mLuminanceCalculator;
|
||||
void dirty() { mDirty = true; }
|
||||
|
||||
const fx::DispatchArray& getPasses() { return mPasses; }
|
||||
|
||||
void setPasses(fx::DispatchArray&& passes);
|
||||
|
||||
void setMask(bool underwater, bool exterior);
|
||||
|
||||
void setTextureScene(osg::ref_ptr<osg::Texture> tex) { mTextureScene = tex; }
|
||||
|
||||
void setTextureDepth(osg::ref_ptr<osg::Texture> tex) { mTextureDepth = tex; }
|
||||
|
||||
void setTextureNormals(osg::ref_ptr<osg::Texture> tex) { mTextureNormals = tex; }
|
||||
|
||||
void setCalculateAvgLum(bool enabled) { mAvgLum = enabled; }
|
||||
|
||||
void setPostProcessing(bool enabled) { mPostprocessing = enabled; }
|
||||
|
||||
const osg::ref_ptr<osg::Texture>& getSceneTexture(size_t frameId) const { return mTextureScene; }
|
||||
|
||||
private:
|
||||
bool mAvgLum = false;
|
||||
bool mPostprocessing = false;
|
||||
|
||||
fx::DispatchArray mPasses;
|
||||
fx::FlagsType mMask;
|
||||
|
||||
osg::ref_ptr<osg::Program> mFallbackProgram;
|
||||
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
|
||||
osg::ref_ptr<osg::StateSet> mFallbackStateSet;
|
||||
osg::ref_ptr<osg::StateSet> mMultiviewResolveStateSet;
|
||||
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
|
||||
|
||||
struct BufferData
|
||||
{
|
||||
bool dirty = false;
|
||||
bool hdr = false;
|
||||
bool postprocessing = true;
|
||||
osg::ref_ptr<osg::Texture> mTextureScene;
|
||||
osg::ref_ptr<osg::Texture> mTextureDepth;
|
||||
osg::ref_ptr<osg::Texture> mTextureNormals;
|
||||
|
||||
fx::DispatchArray data;
|
||||
fx::FlagsType mask;
|
||||
|
||||
osg::ref_ptr<osg::FrameBufferObject> destination;
|
||||
|
||||
osg::ref_ptr<osg::Texture> sceneTex;
|
||||
osg::ref_ptr<osg::Texture> depthTex;
|
||||
osg::ref_ptr<osg::Texture> sceneTexLDR;
|
||||
osg::ref_ptr<osg::Texture> normalsTex;
|
||||
};
|
||||
|
||||
mutable std::array<BufferData, 2> mBufferData;
|
||||
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
|
||||
mutable bool mDirty = false;
|
||||
mutable osg::ref_ptr<osg::Viewport> mRenderViewport;
|
||||
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
|
||||
mutable osg::ref_ptr<osg::FrameBufferObject> mDestinationFBO;
|
||||
mutable std::array<osg::ref_ptr<osg::FrameBufferObject>, 3> mFbos;
|
||||
mutable LuminanceCalculator mLuminanceCalculator;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace MWRender
|
||||
if (Stereo::getStereo())
|
||||
{
|
||||
mViewportStateset = new osg::StateSet();
|
||||
mViewport = new osg::Viewport(0, 0, pp->renderWidth(), pp->renderHeight());
|
||||
mViewport = new osg::Viewport;
|
||||
mViewportStateset->setAttribute(mViewport);
|
||||
}
|
||||
}
|
||||
@ -37,41 +37,31 @@ namespace MWRender
|
||||
size_t frame = cv->getTraversalNumber();
|
||||
size_t frameId = frame % 2;
|
||||
|
||||
MWRender::PostProcessor* postProcessor
|
||||
= dynamic_cast<MWRender::PostProcessor*>(cv->getCurrentCamera()->getUserData());
|
||||
if (!postProcessor)
|
||||
throw std::runtime_error("PingPongCull: failed to get a PostProcessor!");
|
||||
|
||||
if (Stereo::getStereo())
|
||||
{
|
||||
auto& sm = Stereo::Manager::instance();
|
||||
auto view = sm.getEye(cv);
|
||||
int index = view == Stereo::Eye::Right ? 1 : 0;
|
||||
auto projectionMatrix = sm.computeEyeProjection(index, true);
|
||||
postProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
||||
mPostProcessor->getStateUpdater()->setProjectionMatrix(projectionMatrix);
|
||||
}
|
||||
|
||||
postProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
||||
postProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
||||
mPostProcessor->getStateUpdater()->setViewMatrix(cv->getCurrentCamera()->getViewMatrix());
|
||||
mPostProcessor->getStateUpdater()->setPrevViewMatrix(mLastViewMatrix[0]);
|
||||
mLastViewMatrix[0] = cv->getCurrentCamera()->getViewMatrix();
|
||||
|
||||
postProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
||||
postProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
||||
mPostProcessor->getStateUpdater()->setEyePos(cv->getEyePoint());
|
||||
mPostProcessor->getStateUpdater()->setEyeVec(cv->getLookVectorLocal());
|
||||
|
||||
if (!postProcessor->getFbo(PostProcessor::FBO_Primary, frameId))
|
||||
if (!mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
||||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(nullptr);
|
||||
renderStage->setFrameBufferObject(nullptr);
|
||||
}
|
||||
else if (!postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId))
|
||||
{
|
||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
}
|
||||
else
|
||||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(
|
||||
postProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
renderStage->setFrameBufferObject(postProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
|
||||
mPostProcessor->getFbo(PostProcessor::FBO_Primary, frameId));
|
||||
renderStage->setFrameBufferObject(mPostProcessor->getFbo(PostProcessor::FBO_Multisample, frameId));
|
||||
|
||||
// The MultiView patch has a bug where it does not update resolve layers if the resolve framebuffer is
|
||||
// changed. So we do blit manually in this case
|
||||
|
@ -110,30 +110,45 @@ namespace MWRender
|
||||
PostProcessor::PostProcessor(
|
||||
RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs)
|
||||
: osg::Group()
|
||||
, mEnableLiveReload(false)
|
||||
, mRootNode(rootNode)
|
||||
, mSamples(Settings::video().mAntialiasing)
|
||||
, mDirty(false)
|
||||
, mDirtyFrameId(0)
|
||||
, mHUDCamera(new osg::Camera)
|
||||
, mRendering(rendering)
|
||||
, mViewer(viewer)
|
||||
, mVFS(vfs)
|
||||
, mTriggerShaderReload(false)
|
||||
, mReload(false)
|
||||
, mEnabled(false)
|
||||
, mUsePostProcessing(Settings::postProcessing().mEnabled)
|
||||
, mDisableDepthPasses(false)
|
||||
, mLastFrameNumber(0)
|
||||
, mLastSimulationTime(0.f)
|
||||
, mExteriorFlag(false)
|
||||
, mUnderwater(false)
|
||||
, mHDR(false)
|
||||
, mNormals(false)
|
||||
, mPrevNormals(false)
|
||||
, mNormalsSupported(false)
|
||||
, mPassLights(false)
|
||||
, mPrevPassLights(false)
|
||||
, mSamples(Settings::video().mAntialiasing)
|
||||
, mPingPongCull(new PingPongCull(this))
|
||||
, mCanvases({ new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()),
|
||||
new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager()) })
|
||||
{
|
||||
mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);
|
||||
mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0));
|
||||
mHUDCamera->setClearMask(0);
|
||||
mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||
mHUDCamera->setAllowEventFocus(false);
|
||||
mHUDCamera->setViewport(0, 0, mWidth, mHeight);
|
||||
mHUDCamera->setNodeMask(Mask_RenderToTexture);
|
||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
mHUDCamera->addChild(mCanvases[0]);
|
||||
mHUDCamera->addChild(mCanvases[1]);
|
||||
mHUDCamera->setCullCallback(new HUDCullCallback);
|
||||
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
||||
|
||||
if (Settings::shaders().mSoftParticles || Settings::postProcessing().mTransparentPostpass)
|
||||
{
|
||||
mTransparentDepthPostPass
|
||||
= new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(),
|
||||
Settings::postProcessing().mTransparentPostpass);
|
||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
||||
}
|
||||
|
||||
createObjectsForFrame(0);
|
||||
createObjectsForFrame(1);
|
||||
|
||||
populateTechniqueFiles();
|
||||
|
||||
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
|
||||
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
|
||||
|
||||
@ -169,11 +184,18 @@ namespace MWRender
|
||||
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
|
||||
mStateUpdater = new fx::StateUpdater(mUBO);
|
||||
|
||||
if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles
|
||||
&& !mUsePostProcessing)
|
||||
return;
|
||||
addChild(mHUDCamera);
|
||||
addChild(mRootNode);
|
||||
|
||||
enable(mUsePostProcessing);
|
||||
mViewer->setSceneData(this);
|
||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this));
|
||||
mViewer->getCamera()->setUserData(this);
|
||||
|
||||
setCullCallback(mStateUpdater);
|
||||
|
||||
if (mUsePostProcessing)
|
||||
enable();
|
||||
}
|
||||
|
||||
PostProcessor::~PostProcessor()
|
||||
@ -202,7 +224,6 @@ namespace MWRender
|
||||
|
||||
size_t frameId = frame() % 2;
|
||||
|
||||
createTexturesAndCamera(frameId);
|
||||
createObjectsForFrame(frameId);
|
||||
|
||||
mRendering.updateProjectionMatrix();
|
||||
@ -210,8 +231,6 @@ namespace MWRender
|
||||
|
||||
dirtyTechniques();
|
||||
|
||||
mPingPongCanvas->dirty(frameId);
|
||||
|
||||
mDirty = true;
|
||||
mDirtyFrameId = !frameId;
|
||||
}
|
||||
@ -230,77 +249,20 @@ namespace MWRender
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessor::enable(bool usePostProcessing)
|
||||
void PostProcessor::enable()
|
||||
{
|
||||
mReload = true;
|
||||
mEnabled = true;
|
||||
const bool postPass = Settings::postProcessing().mTransparentPostpass;
|
||||
mUsePostProcessing = usePostProcessing;
|
||||
|
||||
mDisableDepthPasses = !Settings::shaders().mSoftParticles && !postPass;
|
||||
|
||||
#ifdef ANDROID
|
||||
mDisableDepthPasses = true;
|
||||
#endif
|
||||
|
||||
if (!mDisableDepthPasses)
|
||||
{
|
||||
mTransparentDepthPostPass = new TransparentDepthBinCallback(
|
||||
mRendering.getResourceSystem()->getSceneManager()->getShaderManager(), postPass);
|
||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(mTransparentDepthPostPass);
|
||||
}
|
||||
|
||||
if (mUsePostProcessing && mTechniqueFileMap.empty())
|
||||
{
|
||||
populateTechniqueFiles();
|
||||
}
|
||||
|
||||
createTexturesAndCamera(frame() % 2);
|
||||
|
||||
removeChild(mHUDCamera);
|
||||
removeChild(mRootNode);
|
||||
|
||||
addChild(mHUDCamera);
|
||||
addChild(mRootNode);
|
||||
|
||||
mViewer->setSceneData(this);
|
||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this));
|
||||
mViewer->getCamera()->setUserData(this);
|
||||
|
||||
setCullCallback(mStateUpdater);
|
||||
mHUDCamera->setCullCallback(new HUDCullCallback);
|
||||
mUsePostProcessing = true;
|
||||
}
|
||||
|
||||
void PostProcessor::disable()
|
||||
{
|
||||
if (!Settings::shaders().mSoftParticles)
|
||||
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr);
|
||||
|
||||
if (!SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles)
|
||||
{
|
||||
removeChild(mHUDCamera);
|
||||
setCullCallback(nullptr);
|
||||
|
||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER);
|
||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(nullptr);
|
||||
mViewer->getCamera()->setUserData(nullptr);
|
||||
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
mUsePostProcessing = false;
|
||||
mRendering.getSkyManager()->setSunglare(true);
|
||||
}
|
||||
|
||||
void PostProcessor::traverse(osg::NodeVisitor& nv)
|
||||
{
|
||||
if (!mEnabled)
|
||||
{
|
||||
osg::Group::traverse(nv);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t frameId = nv.getTraversalNumber() % 2;
|
||||
|
||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||
@ -313,26 +275,23 @@ namespace MWRender
|
||||
|
||||
void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv)
|
||||
{
|
||||
const auto& fbo = getFbo(FBO_Intercept, frameId);
|
||||
if (fbo)
|
||||
if (const auto& fbo = getFbo(FBO_Intercept, frameId))
|
||||
{
|
||||
osgUtil::RenderStage* rs = cv->getRenderStage();
|
||||
if (rs && rs->getMultisampleResolveFramebufferObject())
|
||||
rs->setMultisampleResolveFramebufferObject(fbo);
|
||||
}
|
||||
|
||||
mPingPongCanvas->setPostProcessing(frameId, mUsePostProcessing);
|
||||
mPingPongCanvas->setNormalsTexture(frameId, mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
||||
mPingPongCanvas->setMask(frameId, mUnderwater, mExteriorFlag);
|
||||
mPingPongCanvas->setHDR(frameId, getHDR());
|
||||
mCanvases[frameId]->setPostProcessing(mUsePostProcessing);
|
||||
mCanvases[frameId]->setTextureNormals(mNormals ? getTexture(Tex_Normal, frameId) : nullptr);
|
||||
mCanvases[frameId]->setMask(mUnderwater, mExteriorFlag);
|
||||
mCanvases[frameId]->setCalculateAvgLum(mHDR);
|
||||
|
||||
mPingPongCanvas->setSceneTexture(frameId, getTexture(Tex_Scene, frameId));
|
||||
if (mDisableDepthPasses)
|
||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_Depth, frameId));
|
||||
mCanvases[frameId]->setTextureScene(getTexture(Tex_Scene, frameId));
|
||||
if (mTransparentDepthPostPass)
|
||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_OpaqueDepth, frameId));
|
||||
else
|
||||
mPingPongCanvas->setDepthTexture(frameId, getTexture(Tex_OpaqueDepth, frameId));
|
||||
|
||||
mPingPongCanvas->setLDRSceneTexture(frameId, getTexture(Tex_Scene_LDR, frameId));
|
||||
mCanvases[frameId]->setTextureDepth(getTexture(Tex_Depth, frameId));
|
||||
|
||||
if (mTransparentDepthPostPass)
|
||||
{
|
||||
@ -355,7 +314,7 @@ namespace MWRender
|
||||
mStateUpdater->setDeltaSimulationTime(static_cast<float>(stamp->getSimulationTime() - mLastSimulationTime));
|
||||
mLastSimulationTime = stamp->getSimulationTime();
|
||||
|
||||
for (const auto& dispatchNode : mPingPongCanvas->getCurrentFrameData(frame))
|
||||
for (const auto& dispatchNode : mCanvases[frameId]->getPasses())
|
||||
{
|
||||
for (auto& uniform : dispatchNode.mHandle->getUniformMap())
|
||||
{
|
||||
@ -421,13 +380,15 @@ namespace MWRender
|
||||
|
||||
reloadIfRequired();
|
||||
|
||||
mCanvases[frameId]->setNodeMask(~0u);
|
||||
mCanvases[!frameId]->setNodeMask(0);
|
||||
|
||||
if (mDirty && mDirtyFrameId == frameId)
|
||||
{
|
||||
createTexturesAndCamera(frameId);
|
||||
createObjectsForFrame(frameId);
|
||||
mDirty = false;
|
||||
|
||||
mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData));
|
||||
mDirty = false;
|
||||
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
|
||||
}
|
||||
|
||||
if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights))
|
||||
@ -448,7 +409,6 @@ namespace MWRender
|
||||
|
||||
mViewer->startThreading();
|
||||
|
||||
createTexturesAndCamera(frameId);
|
||||
createObjectsForFrame(frameId);
|
||||
|
||||
mDirty = true;
|
||||
@ -458,19 +418,55 @@ namespace MWRender
|
||||
|
||||
void PostProcessor::createObjectsForFrame(size_t frameId)
|
||||
{
|
||||
auto& fbos = mFbos[frameId];
|
||||
auto& textures = mTextures[frameId];
|
||||
auto width = renderWidth();
|
||||
auto height = renderHeight();
|
||||
|
||||
for (auto& tex : textures)
|
||||
int width = renderWidth();
|
||||
int height = renderHeight();
|
||||
|
||||
for (osg::ref_ptr<osg::Texture>& texture : textures)
|
||||
{
|
||||
if (!tex)
|
||||
continue;
|
||||
|
||||
Stereo::setMultiviewCompatibleTextureSize(tex, width, height);
|
||||
tex->dirtyTextureObject();
|
||||
if (!texture)
|
||||
{
|
||||
if (Stereo::getMultiview())
|
||||
texture = new osg::Texture2DArray;
|
||||
else
|
||||
texture = new osg::Texture2D;
|
||||
}
|
||||
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||
texture->setSourceFormat(GL_RGBA);
|
||||
texture->setSourceType(GL_UNSIGNED_BYTE);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
|
||||
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setResizeNonPowerOfTwoHint(false);
|
||||
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||
texture->dirtyTextureObject();
|
||||
}
|
||||
|
||||
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
||||
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
||||
|
||||
auto setupDepth = [](osg::Texture* tex) {
|
||||
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
||||
tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat());
|
||||
};
|
||||
|
||||
setupDepth(textures[Tex_Depth]);
|
||||
|
||||
if (!mTransparentDepthPostPass)
|
||||
{
|
||||
textures[Tex_OpaqueDepth] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
setupDepth(textures[Tex_OpaqueDepth]);
|
||||
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
||||
}
|
||||
|
||||
auto& fbos = mFbos[frameId];
|
||||
|
||||
fbos[FBO_Primary] = new osg::FrameBufferObject;
|
||||
fbos[FBO_Primary]->setAttachment(
|
||||
@ -534,13 +530,12 @@ namespace MWRender
|
||||
osg::FrameBufferAttachment(new osg::RenderBuffer(textures[Tex_OpaqueDepth]->getTextureWidth(),
|
||||
textures[Tex_OpaqueDepth]->getTextureHeight(), textures[Tex_Scene]->getInternalFormat())));
|
||||
#endif
|
||||
|
||||
mCanvases[frameId]->dirty();
|
||||
}
|
||||
|
||||
void PostProcessor::dirtyTechniques()
|
||||
{
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
size_t frameId = frame() % 2;
|
||||
|
||||
mDirty = true;
|
||||
@ -667,7 +662,7 @@ namespace MWRender
|
||||
mTemplateData.emplace_back(std::move(node));
|
||||
}
|
||||
|
||||
mPingPongCanvas->setCurrentFrameData(frameId, fx::DispatchArray(mTemplateData));
|
||||
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
|
||||
|
||||
if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud())
|
||||
hud->updateTechniques();
|
||||
@ -678,12 +673,6 @@ namespace MWRender
|
||||
PostProcessor::Status PostProcessor::enableTechnique(
|
||||
std::shared_ptr<fx::Technique> technique, std::optional<int> location)
|
||||
{
|
||||
if (!isEnabled())
|
||||
{
|
||||
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << technique->getName() << "'";
|
||||
return Status_Error;
|
||||
}
|
||||
|
||||
if (!technique || technique->getLocked() || (location.has_value() && location.value() < 0))
|
||||
return Status_Error;
|
||||
|
||||
@ -721,86 +710,8 @@ namespace MWRender
|
||||
return technique->isValid();
|
||||
}
|
||||
|
||||
void PostProcessor::createTexturesAndCamera(size_t frameId)
|
||||
{
|
||||
auto& textures = mTextures[frameId];
|
||||
|
||||
auto width = renderWidth();
|
||||
auto height = renderHeight();
|
||||
|
||||
for (auto& texture : textures)
|
||||
{
|
||||
if (!texture)
|
||||
{
|
||||
if (Stereo::getMultiview())
|
||||
texture = new osg::Texture2DArray;
|
||||
else
|
||||
texture = new osg::Texture2D;
|
||||
}
|
||||
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||
texture->setSourceFormat(GL_RGBA);
|
||||
texture->setSourceType(GL_UNSIGNED_BYTE);
|
||||
texture->setInternalFormat(GL_RGBA);
|
||||
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture::LINEAR);
|
||||
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture::LINEAR);
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setResizeNonPowerOfTwoHint(false);
|
||||
}
|
||||
|
||||
textures[Tex_Normal]->setSourceFormat(GL_RGB);
|
||||
textures[Tex_Normal]->setInternalFormat(GL_RGB);
|
||||
|
||||
auto setupDepth = [](osg::Texture* tex) {
|
||||
tex->setSourceFormat(GL_DEPTH_STENCIL_EXT);
|
||||
tex->setSourceType(SceneUtil::AutoDepth::depthSourceType());
|
||||
tex->setInternalFormat(SceneUtil::AutoDepth::depthInternalFormat());
|
||||
};
|
||||
|
||||
setupDepth(textures[Tex_Depth]);
|
||||
|
||||
if (mDisableDepthPasses)
|
||||
{
|
||||
textures[Tex_OpaqueDepth] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
setupDepth(textures[Tex_OpaqueDepth]);
|
||||
textures[Tex_OpaqueDepth]->setName("opaqueTexMap");
|
||||
}
|
||||
|
||||
if (mHUDCamera)
|
||||
return;
|
||||
|
||||
mHUDCamera = new osg::Camera;
|
||||
mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);
|
||||
mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0));
|
||||
mHUDCamera->setClearMask(0);
|
||||
mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
|
||||
mHUDCamera->setAllowEventFocus(false);
|
||||
mHUDCamera->setViewport(0, 0, mWidth, mHeight);
|
||||
|
||||
mViewer->getCamera()->removeCullCallback(mPingPongCull);
|
||||
mPingPongCull = new PingPongCull(this);
|
||||
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
||||
|
||||
mPingPongCanvas = new PingPongCanvas(mRendering.getResourceSystem()->getSceneManager()->getShaderManager());
|
||||
mHUDCamera->addChild(mPingPongCanvas);
|
||||
mHUDCamera->setNodeMask(Mask_RenderToTexture);
|
||||
|
||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
mHUDCamera->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(const std::string& name, bool loadNextFrame)
|
||||
{
|
||||
if (!isEnabled())
|
||||
{
|
||||
Log(Debug::Warning) << "PostProcessing disabled, cannot load technique '" << name << "'";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const auto& technique : mTemplates)
|
||||
if (Misc::StringUtils::ciEqual(technique->getName(), name))
|
||||
return technique;
|
||||
@ -831,9 +742,6 @@ namespace MWRender
|
||||
|
||||
void PostProcessor::loadChain()
|
||||
{
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
mTechniques.clear();
|
||||
|
||||
for (const std::string& techniqueName : Settings::postProcessing().mChain.get())
|
||||
|
@ -115,14 +115,14 @@ namespace MWRender
|
||||
return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary];
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Camera> getHUDCamera() { return mHUDCamera; }
|
||||
|
||||
osg::ref_ptr<fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
|
||||
|
||||
const TechniqueList& getTechniques() { return mTechniques; }
|
||||
|
||||
const TechniqueList& getTemplates() const { return mTemplates; }
|
||||
|
||||
osg::ref_ptr<PingPongCanvas> getCanvas() { return mPingPongCanvas; }
|
||||
|
||||
const auto& getTechniqueMap() const { return mTechniqueFileMap; }
|
||||
|
||||
void resize();
|
||||
@ -173,13 +173,11 @@ namespace MWRender
|
||||
|
||||
std::shared_ptr<fx::Technique> loadTechnique(const std::string& name, bool loadNextFrame = false);
|
||||
|
||||
bool isEnabled() const { return mUsePostProcessing && mEnabled; }
|
||||
|
||||
bool getHDR() const { return mHDR; }
|
||||
bool isEnabled() const { return mUsePostProcessing; }
|
||||
|
||||
void disable();
|
||||
|
||||
void enable(bool usePostProcessing = true);
|
||||
void enable();
|
||||
|
||||
void setRenderTargetSize(int width, int height)
|
||||
{
|
||||
@ -194,7 +192,7 @@ namespace MWRender
|
||||
|
||||
void triggerShaderReload();
|
||||
|
||||
bool mEnableLiveReload;
|
||||
bool mEnableLiveReload = false;
|
||||
|
||||
void loadChain();
|
||||
void saveChain();
|
||||
@ -206,10 +204,6 @@ namespace MWRender
|
||||
|
||||
void createObjectsForFrame(size_t frameId);
|
||||
|
||||
void createTexturesAndCamera(size_t frameId);
|
||||
|
||||
void reloadMainPass(fx::Technique& technique);
|
||||
|
||||
void dirtyTechniques();
|
||||
|
||||
void update(size_t frameId);
|
||||
@ -232,43 +226,39 @@ namespace MWRender
|
||||
|
||||
std::unordered_map<std::string, std::filesystem::path> mTechniqueFileMap;
|
||||
|
||||
int mSamples;
|
||||
|
||||
bool mDirty;
|
||||
size_t mDirtyFrameId;
|
||||
|
||||
RenderingManager& mRendering;
|
||||
osgViewer::Viewer* mViewer;
|
||||
const VFS::Manager* mVFS;
|
||||
|
||||
bool mTriggerShaderReload;
|
||||
bool mReload;
|
||||
bool mEnabled;
|
||||
bool mUsePostProcessing;
|
||||
bool mDisableDepthPasses;
|
||||
size_t mDirtyFrameId = 0;
|
||||
size_t mLastFrameNumber = 0;
|
||||
float mLastSimulationTime = 0.f;
|
||||
|
||||
size_t mLastFrameNumber;
|
||||
float mLastSimulationTime;
|
||||
bool mDirty = false;
|
||||
bool mReload = true;
|
||||
bool mTriggerShaderReload = false;
|
||||
bool mUsePostProcessing = false;
|
||||
|
||||
bool mUBO = false;
|
||||
bool mHDR = false;
|
||||
bool mNormals = false;
|
||||
bool mUnderwater = false;
|
||||
bool mPassLights = false;
|
||||
bool mPrevNormals = false;
|
||||
bool mExteriorFlag = false;
|
||||
bool mNormalsSupported = false;
|
||||
bool mPrevPassLights = false;
|
||||
|
||||
bool mExteriorFlag;
|
||||
bool mUnderwater;
|
||||
bool mHDR;
|
||||
bool mNormals;
|
||||
bool mPrevNormals;
|
||||
bool mNormalsSupported;
|
||||
bool mPassLights;
|
||||
bool mPrevPassLights;
|
||||
bool mUBO;
|
||||
int mGLSLVersion;
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
int mSamples;
|
||||
|
||||
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
|
||||
osg::ref_ptr<PingPongCull> mPingPongCull;
|
||||
osg::ref_ptr<PingPongCanvas> mPingPongCanvas;
|
||||
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
||||
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
|
||||
fx::DispatchArray mTemplateData;
|
||||
};
|
||||
}
|
||||
|
@ -1256,7 +1256,7 @@ namespace MWRender
|
||||
mSharedUniformStateUpdater->setScreenRes(res.x(), res.y());
|
||||
Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix());
|
||||
}
|
||||
else if (!mPostProcessor->isEnabled())
|
||||
else
|
||||
{
|
||||
mSharedUniformStateUpdater->setScreenRes(width, height);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "postprocessor.hpp"
|
||||
#include "util.hpp"
|
||||
@ -102,24 +103,6 @@ namespace MWRender
|
||||
int width = screenW - leftPadding * 2;
|
||||
int height = screenH - topPadding * 2;
|
||||
|
||||
// Ensure we are reading from the resolved framebuffer and not the multisampled render buffer. Also ensure
|
||||
// that the readbuffer is set correctly with rendeirng to FBO. glReadPixel() cannot read from multisampled
|
||||
// targets
|
||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
osg::GLExtensions* ext = osg::GLExtensions::Get(renderInfo.getContextID(), false);
|
||||
|
||||
if (ext)
|
||||
{
|
||||
size_t frameId = renderInfo.getState()->getFrameStamp()->getFrameNumber() % 2;
|
||||
osg::FrameBufferObject* fbo = nullptr;
|
||||
|
||||
if (postProcessor && postProcessor->getFbo(PostProcessor::FBO_Primary, frameId))
|
||||
fbo = postProcessor->getFbo(PostProcessor::FBO_Primary, frameId);
|
||||
|
||||
if (fbo)
|
||||
fbo->apply(*renderInfo.getState(), osg::FrameBufferObject::READ_FRAMEBUFFER);
|
||||
}
|
||||
|
||||
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
|
||||
mImage->scaleImage(mWidth, mHeight, 1);
|
||||
}
|
||||
@ -145,7 +128,7 @@ namespace MWRender
|
||||
|
||||
void ScreenshotManager::screenshot(osg::Image* image, int w, int h)
|
||||
{
|
||||
osg::Camera* camera = mViewer->getCamera();
|
||||
osg::Camera* camera = MWBase::Environment::get().getWorld()->getPostProcessor()->getHUDCamera();
|
||||
osg::ref_ptr<osg::Drawable> tempDrw = new osg::Drawable;
|
||||
tempDrw->setDrawCallback(new ReadImageFromFramebufferCallback(image, w, h));
|
||||
tempDrw->setCullingActive(false);
|
||||
|
@ -145,6 +145,8 @@ namespace Settings
|
||||
|
||||
void Manager::clear()
|
||||
{
|
||||
sInitialized.clear();
|
||||
StaticValues::clear();
|
||||
mDefaultSettings.clear();
|
||||
mUserSettings.clear();
|
||||
mChangedSettings.clear();
|
||||
|
@ -4,24 +4,29 @@
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
Index* StaticValues::sIndex = nullptr;
|
||||
Values* StaticValues::sValues = nullptr;
|
||||
std::unique_ptr<Index> StaticValues::sIndex;
|
||||
std::unique_ptr<Values> StaticValues::sDefaultValues;
|
||||
std::unique_ptr<Values> StaticValues::sValues;
|
||||
|
||||
void StaticValues::initDefaults()
|
||||
{
|
||||
if (sValues != nullptr)
|
||||
throw std::logic_error("Default settings already initialized");
|
||||
static Index index;
|
||||
static Values values(index);
|
||||
sIndex = &index;
|
||||
sValues = &values;
|
||||
if (sDefaultValues != nullptr)
|
||||
throw std::logic_error("Default settings are already initialized");
|
||||
sIndex = std::make_unique<Index>();
|
||||
sDefaultValues = std::make_unique<Values>(*sIndex);
|
||||
}
|
||||
|
||||
void StaticValues::init()
|
||||
{
|
||||
if (sValues == nullptr)
|
||||
if (sDefaultValues == nullptr)
|
||||
throw std::logic_error("Default settings are not initialized");
|
||||
static Values values(std::move(*sValues));
|
||||
sValues = &values;
|
||||
sValues = std::make_unique<Values>(std::move(*sDefaultValues));
|
||||
}
|
||||
|
||||
void StaticValues::clear()
|
||||
{
|
||||
sValues = nullptr;
|
||||
sDefaultValues = nullptr;
|
||||
sIndex = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "settingvalue.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace Settings
|
||||
@ -71,9 +72,12 @@ namespace Settings
|
||||
|
||||
static void init();
|
||||
|
||||
static void clear();
|
||||
|
||||
private:
|
||||
static Index* sIndex;
|
||||
static Values* sValues;
|
||||
static std::unique_ptr<Index> sIndex;
|
||||
static std::unique_ptr<Values> sDefaultValues;
|
||||
static std::unique_ptr<Values> sValues;
|
||||
|
||||
friend Values& values();
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace Gui
|
||||
}
|
||||
else
|
||||
{
|
||||
TextBox::setPropertyOverride(_key, _value);
|
||||
Gui::TextBox::setPropertyOverride(_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ namespace Gui
|
||||
}
|
||||
else
|
||||
{
|
||||
EditBox::setPropertyOverride(_key, _value);
|
||||
Gui::EditBox::setPropertyOverride(_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ namespace Gui
|
||||
}
|
||||
else
|
||||
{
|
||||
Button::setPropertyOverride(_key, _value);
|
||||
Gui::Button::setPropertyOverride(_key, _value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,25 @@
|
||||
#include <MyGUI_TextBox.h>
|
||||
#include <MyGUI_Widget.h>
|
||||
|
||||
#include "fontwrapper.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class Button : public FontWrapper<MyGUI::Button>
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(Button)
|
||||
};
|
||||
|
||||
class TextBox : public FontWrapper<MyGUI::TextBox>
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(TextBox)
|
||||
};
|
||||
|
||||
class EditBox : public FontWrapper<MyGUI::EditBox>
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(EditBox)
|
||||
};
|
||||
|
||||
class AutoSizedWidget
|
||||
{
|
||||
public:
|
||||
@ -27,7 +44,7 @@ namespace Gui
|
||||
MyGUI::Align mExpandDirection;
|
||||
};
|
||||
|
||||
class AutoSizedTextBox : public AutoSizedWidget, public MyGUI::TextBox
|
||||
class AutoSizedTextBox : public AutoSizedWidget, public TextBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(AutoSizedTextBox)
|
||||
|
||||
@ -40,7 +57,7 @@ namespace Gui
|
||||
std::string mFontSize;
|
||||
};
|
||||
|
||||
class AutoSizedEditBox : public AutoSizedWidget, public MyGUI::EditBox
|
||||
class AutoSizedEditBox : public AutoSizedWidget, public EditBox
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(AutoSizedEditBox)
|
||||
|
||||
@ -59,7 +76,7 @@ namespace Gui
|
||||
int mMaxWidth = 0;
|
||||
};
|
||||
|
||||
class AutoSizedButton : public AutoSizedWidget, public MyGUI::Button
|
||||
class AutoSizedButton : public AutoSizedWidget, public Button
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(AutoSizedButton)
|
||||
|
||||
|
25
components/widgets/fontwrapper.hpp
Normal file
25
components/widgets/fontwrapper.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef OPENMW_WIDGETS_WRAPPER_H
|
||||
#define OPENMW_WIDGETS_WRAPPER_H
|
||||
|
||||
#include <MyGUI_Prerequest.h>
|
||||
|
||||
#include "components/settings/values.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
/// Wrapper to tell UI element to use font size from settings.cfg
|
||||
template <class T>
|
||||
class FontWrapper : public T
|
||||
{
|
||||
public:
|
||||
void setFontName(std::string_view name) override
|
||||
{
|
||||
T::setFontName(name);
|
||||
T::setPropertyOverride("FontHeight", std::to_string(Settings::gui().mFontSize));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -3,13 +3,15 @@
|
||||
|
||||
#include <MyGUI_EditBox.h>
|
||||
|
||||
#include "fontwrapper.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A variant of the EditBox that only allows integer inputs
|
||||
*/
|
||||
class NumericEditBox final : public MyGUI::EditBox
|
||||
class NumericEditBox final : public FontWrapper<MyGUI::EditBox>
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(NumericEditBox)
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <MyGUI_Button.h>
|
||||
|
||||
#include "fontwrapper.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
||||
@ -12,7 +14,7 @@ namespace Gui
|
||||
|
||||
/// @brief A button that applies its own state changes to other widgets, to do this you define it as part of a
|
||||
/// ButtonGroup.
|
||||
class SharedStateButton final : public MyGUI::Button
|
||||
class SharedStateButton final : public FontWrapper<MyGUI::Button>
|
||||
{
|
||||
MYGUI_RTTI_DERIVED(SharedStateButton)
|
||||
|
||||
|
@ -18,9 +18,12 @@ namespace Gui
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::HBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::Spacer>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::VBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::EditBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::TextBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::AutoSizedTextBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::AutoSizedEditBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::AutoSizedButton>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::Button>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::ImageButton>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::NumericEditBox>("Widget");
|
||||
MyGUI::FactoryManager::getInstance().registerFactory<Gui::SharedStateButton>("Widget");
|
||||
|
@ -318,7 +318,7 @@ Exactly one ``technique`` block is required for every shader file. In this we de
|
||||
+------------------+--------------------+---------------------------------------------------+
|
||||
| author | string | Shader authors that shows in HUD |
|
||||
+------------------+--------------------+---------------------------------------------------+
|
||||
| glsl_Version | integer | GLSL version |
|
||||
| glsl_version | integer | GLSL version |
|
||||
+------------------+--------------------+---------------------------------------------------+
|
||||
| glsl_profile | string | GLSL profile, like ``compatibility`` |
|
||||
+------------------+--------------------+---------------------------------------------------+
|
||||
@ -625,7 +625,6 @@ together passes, setting up metadata, and setting up various flags.
|
||||
passes = desaturate;
|
||||
version = "1.0";
|
||||
author = "Fargoth";
|
||||
passes = desaturate;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user