void ShaderTextEditor::_code_complete_script(const String &p_code, List<String> *r_options) { _check_shader_mode(); ShaderLanguage sl; String calltip; Error err = sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), r_options, calltip); if (err != OK) ERR_PRINT("Shaderlang complete failed"); if (calltip != "") { get_text_edit()->set_code_hint(calltip); } }
void ShaderTextEditor::_validate_script() { _check_shader_mode(); String code = get_text_edit()->get_text(); //List<StringName> params; //shader->get_param_list(¶ms); ShaderLanguage sl; Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(VisualServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types()); if (err != OK) { String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); set_error(error_text); set_error_pos(sl.get_error_line() - 1, 0); for (int i = 0; i < get_text_edit()->get_line_count(); i++) get_text_edit()->set_line_as_marked(i, false); get_text_edit()->set_line_as_marked(sl.get_error_line() - 1, true); } else { for (int i = 0; i < get_text_edit()->get_line_count(); i++) get_text_edit()->set_line_as_marked(i, false); set_error(""); } emit_signal("script_changed"); }
/** * @brief * Constructor */ SPRTTShaders::SPRTTShaders(Renderer &cRenderer) : SPRTT(cRenderer), m_pRenderTarget(nullptr), m_pColorTarget1(nullptr), m_pColorTarget2(nullptr), m_pColorTarget3(nullptr), m_pSceneVertexShader(nullptr), m_pSceneFragmentShader(nullptr), m_pSceneProgram(nullptr), m_pVertexShader(nullptr), m_pFragmentShader(nullptr), m_pProgram(nullptr) { // Check/get number of supported color render targets uint8 nMaxColorTargets = 4; if (nMaxColorTargets > cRenderer.GetCapabilities().nMaxColorRenderTargets) nMaxColorTargets = cRenderer.GetCapabilities().nMaxColorRenderTargets; { // Render targets // Create the render target. We will create a very low resolution 2D texture buffer to see funny pixels. m_pRenderTarget = cRenderer.CreateSurfaceTextureBuffer2D(Vector2i(64, 64), TextureBuffer::R8G8B8, SurfaceTextureBuffer::Depth|SurfaceTextureBuffer::NoMultisampleAntialiasing, nMaxColorTargets); if (m_pRenderTarget && nMaxColorTargets > 1) { // Set additional color render targets if (nMaxColorTargets > 1 && !m_pColorTarget1) { Image cImage = Image::CreateImage(DataByte, ColorRGB, Vector3i(64, 64, 1)); m_pColorTarget1 = cRenderer.CreateTextureBuffer2D(cImage, TextureBuffer::Unknown, TextureBuffer::RenderTarget); } if (nMaxColorTargets > 2 && !m_pColorTarget2) { Image cImage = Image::CreateImage(DataByte, ColorRGB, Vector3i(64, 64, 1)); m_pColorTarget2 = cRenderer.CreateTextureBuffer2D(cImage, TextureBuffer::Unknown, TextureBuffer::RenderTarget); } if (nMaxColorTargets > 3 && !m_pColorTarget3) { Image cImage = Image::CreateImage(DataByte, ColorRGB, Vector3i(64, 64, 1)); m_pColorTarget3 = cRenderer.CreateTextureBuffer2D(cImage, TextureBuffer::Unknown, TextureBuffer::RenderTarget); } } } // Decide which shader language should be used (for example "GLSL" or "Cg") ShaderLanguage *pShaderLanguage = cRenderer.GetShaderLanguage(cRenderer.GetDefaultShaderLanguage()); if (pShaderLanguage) { { // Scene program (with MRT support) // Construct the string containing the fragment shader definitions String sDefinitions; if (m_pColorTarget1) sDefinitions += "#define MRT_1\n"; if (m_pColorTarget2) sDefinitions += "#define MRT_2\n"; if (m_pColorTarget3) sDefinitions += "#define MRT_3\n"; // Shader source code String sVertexShaderSourceCode; String sFragmentShaderSourceCode; if (pShaderLanguage->GetShaderLanguage() == "GLSL") { #include "SPRTTShaders_GLSL.h" if (cRenderer.GetAPI() == "OpenGL ES 2.0") { // Get shader source codes sVertexShaderSourceCode = "#version 100\n" + sSceneVertexShaderSourceCodeGLSL; sFragmentShaderSourceCode = "#version 100\n" + sDefinitions + sSceneFragmentShaderSourceCodeGLSL; } else { // Remove precision qualifiers so that we're able to use 120 (OpenGL 2.1 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 // -> In here we're using 120 instead of 110 because matrix casts are quite comfortable... sVertexShaderSourceCode = "#version 120\n" + Shader::RemovePrecisionQualifiersFromGLSL(sSceneVertexShaderSourceCodeGLSL); sFragmentShaderSourceCode = "#version 120\n" + sDefinitions + Shader::RemovePrecisionQualifiersFromGLSL(sSceneFragmentShaderSourceCodeGLSL); } } else if (pShaderLanguage->GetShaderLanguage() == "Cg") { #include "SPRTTShaders_Cg.h" sVertexShaderSourceCode = sSceneVertexShaderSourceCodeCg; sFragmentShaderSourceCode = sSceneFragmentShaderSourceCodeCg; } // Create a vertex shader instance // -> I define a Cg profile because when using an GLSL Cg profile (which is the default), the shader is not working correctly on my AMD/ATI ("AMD Catalyst™ 11.3") system while it worked on the tested NVIDIA system... m_pSceneVertexShader = pShaderLanguage->CreateVertexShader(sVertexShaderSourceCode, "arbvp1"); // Create a fragment shader instance // -> I define a Cg profile because when using an GLSL Cg profile (which is the default), the shader is not working correctly on my AMD/ATI ("AMD Catalyst™ 11.3") system while it worked on the tested NVIDIA system... m_pSceneFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode, "arbfp1"); // Create a program instance and assign the created vertex and fragment shaders to it m_pSceneProgram = pShaderLanguage->CreateProgram(m_pSceneVertexShader, m_pSceneFragmentShader); } { // Program // Shader source code String sVertexShaderSourceCode; String sFragmentShaderSourceCode; if (pShaderLanguage->GetShaderLanguage() == "GLSL") { #include "SPRTTShaders_GLSL.h" if (cRenderer.GetAPI() == "OpenGL ES 2.0") { // Get shader source codes sVertexShaderSourceCode = "#version 100\n" + sVertexShaderSourceCodeGLSL; sFragmentShaderSourceCode = "#version 100\n" + sFragmentShaderSourceCodeGLSL; } 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(sVertexShaderSourceCodeGLSL); sFragmentShaderSourceCode = "#version 110\n" + Shader::RemovePrecisionQualifiersFromGLSL(sFragmentShaderSourceCodeGLSL); } } else if (pShaderLanguage->GetShaderLanguage() == "Cg") { #include "SPRTTShaders_Cg.h" sVertexShaderSourceCode = sVertexShaderSourceCodeCg; sFragmentShaderSourceCode = sFragmentShaderSourceCodeCg; } // Create a vertex shader instance // -> I define a Cg profile because when using an GLSL Cg profile (which is the default), the shader is not working correctly on my AMD/ATI ("AMD Catalyst™ 11.3") system while it worked on the tested NVIDIA system... m_pVertexShader = pShaderLanguage->CreateVertexShader(sVertexShaderSourceCode, "arbvp1"); // Create a fragment shader instance // -> I define a Cg profile because when using an GLSL Cg profile (which is the default), the shader is not working correctly on my AMD/ATI ("AMD Catalyst™ 11.3") system while it worked on the tested NVIDIA system... m_pFragmentShader = pShaderLanguage->CreateFragmentShader(sFragmentShaderSourceCode, "arbfp1"); // Create a program instance and assign the created vertex and fragment shaders to it m_pProgram = static_cast<ProgramWrapper*>(pShaderLanguage->CreateProgram(m_pVertexShader, m_pFragmentShader)); } } }
/** * @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(); } } }