void Node::MarkAsDirty(bool recursive, bool scaleChange) { dirty_ = true; SetUniformsNeedUpdate(); OnDirty(); if (scaleChange) OnScaleChange(); if (recursive) for (auto child : children_) child->MarkAsDirty(recursive, scaleChange); }
bool GDocApp<OptionsFmt>::SetDirty(bool Dirty) { if (IsAttached() && (d->Dirty ^ Dirty)) { // Changing... if (Dirty) { // Setting dirty d->Dirty = true; SetCurFile(d->CurFile); } else { // Clearing dirty int Result = LgiMsg(this, LgiLoadString(L_DOCAPP_SAVE_CHANGE, "Do you want to save your changes?"), d->AppName, MB_YESNOCANCEL); if (Result == IDYES) { if (!ValidStr(d->CurFile)) { GMru::OnCommand(IDM_SAVEAS); } else { _SaveFile(d->CurFile); } } else if (Result == IDCANCEL) { return false; } d->Dirty = false; SetCurFile(d->CurFile); } OnDirty(d->Dirty); } return true; }
bool GDocApp<OptionsFmt>::_SaveFile(char *File) { char RealPath[256]; if (ResolveShortcut(File, RealPath, sizeof(RealPath))) { File = RealPath; } else { strcpy_s(RealPath, sizeof(RealPath), File); } bool Status = GMru::_SaveFile(RealPath); if (Status) { d->Dirty = false; SetCurFile(RealPath); OnDirty(d->Dirty); } return Status; }
/** * @brief * Constructor of SPK_PLQuadRendererShaders */ SPK_PLQuadRendererShaders::SPK_PLQuadRendererShaders(PLRenderer::Renderer &cRenderer, const String &sShaderLanguage, float fScaleX, float fScaleY) : SPK_PLQuadRenderer(cRenderer, fScaleX, fScaleY), m_pEventHandlerDirty(new PLCore::EventHandler<PLRenderer::Program*>(&SPK_PLQuadRendererShaders::OnDirty, this)), m_sShaderLanguage(sShaderLanguage), m_pVertexShader(nullptr), m_pFragmentShader(nullptr), m_pProgram(nullptr), m_pPositionProgramAttribute(nullptr), m_pTexCoordProgramAttribute(nullptr), m_pColorProgramAttribute(nullptr), m_pObjectSpaceToClipSpaceMatrixProgramUniform(nullptr), m_pTextureMapProgramUniform(nullptr) { // Get the shader language to use if (!m_sShaderLanguage.GetLength()) m_sShaderLanguage = cRenderer.GetDefaultShaderLanguage(); // Create the GPU program right now? if (!m_pProgram || m_pProgram->GetShaderLanguage() != m_sShaderLanguage) { // If there's an previous instance of the program, destroy it first if (m_pProgram) { delete m_pProgram; m_pProgram = nullptr; } if (m_pFragmentShader) { delete m_pFragmentShader; m_pFragmentShader = nullptr; } if (m_pVertexShader) { delete m_pVertexShader; m_pVertexShader = nullptr; } m_pPositionProgramAttribute = nullptr; m_pTexCoordProgramAttribute = nullptr; m_pColorProgramAttribute = nullptr; m_pObjectSpaceToClipSpaceMatrixProgramUniform = nullptr; m_pTextureMapProgramUniform = nullptr; // Get the shader language instance PLRenderer::ShaderLanguage *pShaderLanguage = cRenderer.GetShaderLanguage(m_sShaderLanguage); if (pShaderLanguage) { // Shader source code String sVertexShaderSourceCode; String sFragmentShaderSourceCode; if (m_sShaderLanguage == "GLSL") { #include "SPK_PLQuadRendererShaders_GLSL.h" if (cRenderer.GetAPI() == "OpenGL ES 2.0") { // Get shader source codes sVertexShaderSourceCode = "#version 100\n" + sSPK_PLQuadRendererShaders_GLSL_VS; sFragmentShaderSourceCode = "#version 100\n" + sSPK_PLQuadRendererShaders_GLSL_FS; } else { // Remove precision qualifiers so that we're able to use 110 (OpenGL 2.0 shaders) instead of 130 (OpenGL 3.0 shaders, // with this version we can keep the precision qualifiers) so that this shader requirements are as low as possible sVertexShaderSourceCode = "#version 110\n" + Shader::RemovePrecisionQualifiersFromGLSL(sSPK_PLQuadRendererShaders_GLSL_VS); sFragmentShaderSourceCode = "#version 110\n" + Shader::RemovePrecisionQualifiersFromGLSL(sSPK_PLQuadRendererShaders_GLSL_FS); } } else if (m_sShaderLanguage == "Cg") { #include "SPK_PLQuadRendererShaders_Cg.h" sVertexShaderSourceCode = sSPK_PLQuadRendererShaders_Cg_VS; sFragmentShaderSourceCode = sSPK_PLQuadRendererShaders_Cg_FS; } // Create a vertex shader instance m_pVertexShader = pShaderLanguage->CreateVertexShader(sVertexShaderSourceCode, "arbvp1"); // Create a fragment shader instance m_pFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode, "arbfp1"); // Create a program instance and assign the created vertex and fragment shaders to it m_pProgram = pShaderLanguage->CreateProgram(m_pVertexShader, m_pFragmentShader); if (m_pProgram) { // Add our nark which will inform us as soon as the program gets dirty m_pProgram->EventDirty.Connect(*m_pEventHandlerDirty); // Get attributes and uniforms OnDirty(m_pProgram); } } } }
/** * @brief * Calculates the logarithmic average luminance */ void HDRAverageLuminance::CalculateAverageLuminance(const String &sShaderLanguage, TextureBufferRectangle &cOriginalTexture, const Color3 &cLuminanceConvert) { // Get the internal texture format to use const TextureBuffer::EPixelFormat nInternalFormat = (cOriginalTexture.GetFormat() == TextureBuffer::R16G16B16A16F) ? TextureBuffer::L16F : TextureBuffer::L32F; // Get the shader language to use String sUsedShaderLanguage = sShaderLanguage; if (!sUsedShaderLanguage.GetLength()) sUsedShaderLanguage = m_pRenderer->GetDefaultShaderLanguage(); // Create the shaders and programs right now? if (!m_pVertexShader || m_pVertexShader->GetShaderLanguage() != sUsedShaderLanguage) { // If there's an previous instance of the program, destroy it first if (m_pDownsampleLogProgram) { delete m_pDownsampleLogProgram; m_pDownsampleLogProgram = nullptr; } if (m_pDownsampleLogFragmentShader) { delete m_pDownsampleLogFragmentShader; m_pDownsampleLogFragmentShader = nullptr; } if (m_pDownsampleProgram) { delete m_pDownsampleProgram; m_pDownsampleProgram = nullptr; } if (m_pDownsampleFragmentShader) { delete m_pDownsampleFragmentShader; m_pDownsampleFragmentShader = nullptr; } if (m_pDownsampleVertexShader) { delete m_pDownsampleVertexShader; m_pDownsampleVertexShader = nullptr; } if (m_pDownsampleExpProgram) { delete m_pDownsampleExpProgram; m_pDownsampleExpProgram = nullptr; } if (m_pDownsampleExpFragmentShader) { delete m_pDownsampleExpFragmentShader; m_pDownsampleExpFragmentShader = nullptr; } if (m_pVertexShader) { delete m_pVertexShader; m_pVertexShader = nullptr; } m_pDownsampleLogPositionProgramAttribute = nullptr; m_pDownsampleLogTextureSizeProgramUniform = nullptr; m_pDownsampleLogTextureProgramUniform = nullptr; m_pDownsampleLogLuminanceConvertProgramUniform = nullptr; m_pDownsampleLogEpsilonProgramUniform = nullptr; m_pDownsamplePositionProgramAttribute = nullptr; m_pDownsampleTextureSizeProgramUniform = nullptr; m_pDownsampleSizeProgramUniform = nullptr; m_pDownsampleTextureProgramUniform = nullptr; m_pDownsampleExpPositionProgramAttribute = nullptr; m_pDownsampleExpTextureSizeProgramUniform = nullptr; m_pDownsampleExpTextureProgramUniform = nullptr; // Get the shader language instance ShaderLanguage *pShaderLanguage = m_pRenderer->GetShaderLanguage(sUsedShaderLanguage); if (pShaderLanguage) { // Shader source code String sVertexShaderSourceCode; String sVertexShaderSourceCode_Downsample; String sFragmentShaderSourceCode_DownsampleLog; String sFragmentShaderSourceCode_Downsample; String sFragmentShaderSourceCode_DownsampleExp; if (sUsedShaderLanguage == "GLSL") { #include "HDRAverageLuminance_GLSL.h" sVertexShaderSourceCode = sHDRAverageLuminance_GLSL_VS; sVertexShaderSourceCode_Downsample = sHDRAverageLuminance_GLSL_VS_Downsample; sFragmentShaderSourceCode_DownsampleLog = sHDRAverageLuminance_GLSL_FS_Common + sHDRAverageLuminance_GLSL_FS_DownsampleLog; sFragmentShaderSourceCode_Downsample = sHDRAverageLuminance_GLSL_FS_Common + sHDRAverageLuminance_GLSL_FS_Downsample; sFragmentShaderSourceCode_DownsampleExp = sHDRAverageLuminance_GLSL_FS_Common + sHDRAverageLuminance_GLSL_FS_DownsampleExp; } else if (sUsedShaderLanguage == "Cg") { #include "HDRAverageLuminance_Cg.h" sVertexShaderSourceCode = sHDRAverageLuminance_Cg_VS; sVertexShaderSourceCode_Downsample = sHDRAverageLuminance_Cg_VS_Downsample; sFragmentShaderSourceCode_DownsampleLog = sHDRAverageLuminance_Cg_FS_Common + sHDRAverageLuminance_Cg_FS_DownsampleLog; sFragmentShaderSourceCode_Downsample = sHDRAverageLuminance_Cg_FS_Common + sHDRAverageLuminance_Cg_FS_Downsample; sFragmentShaderSourceCode_DownsampleExp = sHDRAverageLuminance_Cg_FS_Common + sHDRAverageLuminance_Cg_FS_DownsampleExp; } // Create a vertex shader instance m_pVertexShader = pShaderLanguage->CreateVertexShader(sVertexShaderSourceCode); m_pDownsampleVertexShader = pShaderLanguage->CreateVertexShader(sVertexShaderSourceCode_Downsample); // Create a fragment shader instance m_pDownsampleLogFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode_DownsampleLog); m_pDownsampleFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode_Downsample); m_pDownsampleExpFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode_DownsampleExp); // Create a program instance and assign the created vertex and fragment shaders to it m_pDownsampleLogProgram = pShaderLanguage->CreateProgram(m_pVertexShader, m_pDownsampleLogFragmentShader); if (m_pDownsampleLogProgram) { // Add our nark which will inform us as soon as the program gets dirty m_pDownsampleLogProgram->EventDirty.Connect(EventHandlerDirty); // Get attributes and uniforms OnDirty(m_pDownsampleLogProgram); } m_pDownsampleProgram = pShaderLanguage->CreateProgram(m_pDownsampleVertexShader, m_pDownsampleFragmentShader); if (m_pDownsampleProgram) { // Add our nark which will inform us as soon as the program gets dirty m_pDownsampleProgram->EventDirty.Connect(EventHandlerDirty); // Get attributes and uniforms OnDirty(m_pDownsampleProgram); } m_pDownsampleExpProgram = pShaderLanguage->CreateProgram(m_pVertexShader, m_pDownsampleExpFragmentShader); if (m_pDownsampleExpProgram) { // Add our nark which will inform us as soon as the program gets dirty m_pDownsampleExpProgram->EventDirty.Connect(EventHandlerDirty); // Get attributes and uniforms OnDirty(m_pDownsampleExpProgram); } } } // Create the fullscreen quad instance if required if (!m_pFullscreenQuad) m_pFullscreenQuad = new FullscreenQuad(*m_pRenderer); // Get the vertex buffer of the fullscreen quad VertexBuffer *pVertexBuffer = m_pFullscreenQuad->GetVertexBuffer(); if (pVertexBuffer) { // First step: Downsample 2x2, calculate pixel luminance and log - I don't use a "bilinear filter" because this would mess up the incoming texel data "before" the log calculation was performed! if (m_pRenderer->SetProgram(m_pDownsampleLogProgram)) { // Get the size of the original HDR texture const Vector2i vRTSize = cOriginalTexture.GetSize()/2; if (vRTSize.x != 0 && vRTSize.y != 0) { // Render target size change? if (m_pDownsampleLogRenderTarget && (m_pDownsampleLogRenderTarget->GetSize() != vRTSize || m_pDownsampleLogRenderTarget->GetFormat() != nInternalFormat)) { // Destroy the downsample 2x2 log render target if (m_pDownsampleLogRenderTarget) { delete m_pDownsampleLogRenderTarget; m_pDownsampleLogRenderTarget = nullptr; } } // Create the downsample 2x2 log render target right now? if (!m_pDownsampleLogRenderTarget) m_pDownsampleLogRenderTarget = m_pRenderer->CreateSurfaceTextureBufferRectangle(vRTSize, nInternalFormat, SurfaceTextureBuffer::NoMultisampleAntialiasing); } // Make the downsample 2x2 log render target to the current render target m_pRenderer->SetRenderTarget(m_pDownsampleLogRenderTarget); // Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute" if (m_pDownsampleLogPositionProgramAttribute) m_pDownsampleLogPositionProgramAttribute->Set(pVertexBuffer, PLRenderer::VertexBuffer::Position); // Set the "TextureSize" fragment shader parameter if (m_pDownsampleLogTextureSizeProgramUniform) m_pDownsampleLogTextureSizeProgramUniform->Set(cOriginalTexture.GetSize()); // Set the "Texture" fragment shader parameter if (m_pDownsampleLogTextureProgramUniform) { const int nTextureUnit = m_pDownsampleLogTextureProgramUniform->Set(&cOriginalTexture); if (nTextureUnit >= 0) { m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressU, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressV, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::None); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::None); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None); } } // Set the "LuminanceConvert" fragment shader parameter if (m_pDownsampleLogLuminanceConvertProgramUniform) m_pDownsampleLogLuminanceConvertProgramUniform->Set(cLuminanceConvert); // Set the "Epsilon" fragment shader parameter if (m_pDownsampleLogEpsilonProgramUniform) m_pDownsampleLogEpsilonProgramUniform->Set(0.0001f); // Draw the fullscreen quad m_pFullscreenQuad->Draw(); } Vector2i vFinalTextureSize; TextureBufferRectangle *pFinalTextureBufferRectangle = nullptr; // Second step: Reduce to <4>x<4> if (m_pDownsampleLogRenderTarget && m_pRenderer->SetProgram(m_pDownsampleProgram)) { const uint32 TextureScaleFactor = 2; // Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute" if (m_pDownsamplePositionProgramAttribute) m_pDownsamplePositionProgramAttribute->Set(pVertexBuffer, PLRenderer::VertexBuffer::Position); // Get the size of the original HDR texture const Vector2i vRTSize = m_pDownsampleLogRenderTarget->GetSize()/TextureScaleFactor; if (vRTSize.x != 0 && vRTSize.y != 0) { // Render target size change? if (m_pDownsampleRenderTarget && (m_pDownsampleRenderTarget->GetSize() != vRTSize || m_pDownsampleRenderTarget->GetFormat() != nInternalFormat)) { // Destroy the downsample 4x4 render target if (m_pDownsampleRenderTarget) { delete m_pDownsampleRenderTarget; m_pDownsampleRenderTarget = nullptr; } } // Create the downsample 4x4 render target right now? if (!m_pDownsampleRenderTarget) m_pDownsampleRenderTarget = m_pRenderer->CreateSurfaceTextureBufferRectangle(vRTSize, nInternalFormat, SurfaceTextureBuffer::NoMultisampleAntialiasing); } // Get the maximum size Vector2i vCurrentSize = m_pDownsampleLogRenderTarget->GetSize(); uint32 nSize = Math::Max(vCurrentSize.x, vCurrentSize.y); // Downscale in multiple render passes, we render into m_pDownsampleRenderTarget and m_pDownsampleLogRenderTarget in a ping-pong way bool bRenderTarget = false; for (; nSize>TextureScaleFactor; nSize/=TextureScaleFactor, bRenderTarget=!bRenderTarget, vCurrentSize/=TextureScaleFactor) { // Get the render target we will render into SurfaceTextureBuffer *pRenderTargetTexture = bRenderTarget ? m_pDownsampleLogRenderTarget : m_pDownsampleRenderTarget; // Get the texture buffer we will downscale TextureBufferRectangle *pTextureBufferRectangle = static_cast<TextureBufferRectangle*>(bRenderTarget ? m_pDownsampleRenderTarget->GetTextureBuffer() : m_pDownsampleLogRenderTarget->GetTextureBuffer()); // Set the current render target m_pRenderer->SetRenderTarget(pRenderTargetTexture); // Backup texture width vFinalTextureSize = vCurrentSize/TextureScaleFactor; pFinalTextureBufferRectangle = static_cast<TextureBufferRectangle*>(pRenderTargetTexture->GetTextureBuffer()); // Set the "TextureSize" fragment shader parameter if (m_pDownsampleTextureSizeProgramUniform) m_pDownsampleTextureSizeProgramUniform->Set(vCurrentSize); // Set the "Size" fragment shader parameter if (m_pDownsampleSizeProgramUniform) m_pDownsampleSizeProgramUniform->Set(static_cast<float>(vFinalTextureSize.x)/pRenderTargetTexture->GetSize().x, static_cast<float>(vFinalTextureSize.y)/pRenderTargetTexture->GetSize().y); // Set the "Texture" fragment shader parameter if (m_pDownsampleTextureProgramUniform) { const int nTextureUnit = m_pDownsampleTextureProgramUniform->Set(pTextureBufferRectangle); if (nTextureUnit >= 0) { m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressU, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressV, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::None); // [TODO] Use bilinear filter m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::None); // [TODO] Use bilinear filter m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None); } } // Draw the fullscreen quad m_pFullscreenQuad->Draw(); } } // Third step: Reduce <4>x<4> to <1>x<1> and calculate the exponent if (m_pRenderer->SetProgram(m_pDownsampleExpProgram)) { // Render format change? if (m_pAverageLuminanceTextureBuffer2D && m_pAverageLuminanceTextureBuffer2D->GetFormat() != nInternalFormat) { // Destroy the result render target if (m_pAverageLuminanceTextureBuffer2D) { delete m_pAverageLuminanceTextureBuffer2D; m_pAverageLuminanceTextureBuffer2D = nullptr; } } // Create the result render target right now? if (!m_pAverageLuminanceTextureBuffer2D) m_pAverageLuminanceTextureBuffer2D = m_pRenderer->CreateSurfaceTextureBuffer2D(Vector2i::One, nInternalFormat, SurfaceTextureBuffer::NoMultisampleAntialiasing); // Make the result render target to the current render target m_pRenderer->SetRenderTarget(m_pAverageLuminanceTextureBuffer2D); // Set program vertex attributes, this creates a connection between "Vertex Buffer Attribute" and "Vertex Shader Attribute" if (m_pDownsampleExpPositionProgramAttribute) m_pDownsampleExpPositionProgramAttribute->Set(pVertexBuffer, PLRenderer::VertexBuffer::Position); // Set the "TextureSize" fragment shader parameter if (m_pDownsampleExpTextureSizeProgramUniform) m_pDownsampleExpTextureSizeProgramUniform->Set(vFinalTextureSize); // Set the "Texture" fragment shader parameter if (m_pDownsampleExpTextureProgramUniform) { const int nTextureUnit = m_pDownsampleExpTextureProgramUniform->Set(pFinalTextureBufferRectangle); if (nTextureUnit >= 0) { m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressU, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::AddressV, TextureAddressing::Wrap); m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MagFilter, TextureFiltering::None); // [TODO] Use bilinear filter m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MinFilter, TextureFiltering::None); // [TODO] Use bilinear filter m_pRenderer->SetSamplerState(nTextureUnit, Sampler::MipFilter, TextureFiltering::None); } } // Draw the fullscreen quad m_pFullscreenQuad->Draw(); } } }