//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2012 Ceetron AS // // This library is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at <> // for more details. // //################################################################################################## #include "cvfBase.h" #include "cvfAssert.h" #include "cvfRenderState.h" #include "cvfOpenGL.h" #include "cvfUniform.h" #include "cvfShaderProgram.h" #include "cvfTexture.h" #include "cvfSampler.h" #include "cvfOpenGLCapabilities.h" namespace cvf { //================================================================================================== /// /// \class cvf::RenderState /// \ingroup Render /// /// Base class for classes encapsulating OpenGL state /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RenderState::RenderState(Type type) : m_stateType(type) { CVF_ASSERT(type < COUNT); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RenderState::~RenderState() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RenderState::Type RenderState::type() const { return m_stateType; } //-------------------------------------------------------------------------------------------------- /// Returns true if this render state relies on Fixed Function OpenGL. /// /// The default implementation of this function returns false //-------------------------------------------------------------------------------------------------- bool RenderState::isFixedFunction() const { return false; } //================================================================================================== /// /// \class cvf::Blending /// \ingroup Render /// /// Encapsulate OpenGL blending functions: glEnable(GL_BLEND), glBlendEquation(), glBlendEquationSeparate() /// glBlendFunc(), glBlendFuncSeparate(), glBlendColor() /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml /// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquation.xml /// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendEquationSeparate.xml /// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFunc.xml /// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendFuncSeparate.xml /// \sa http://www.opengl.org/sdk/docs/man3/xhtml/glBlendColor.xml /// /// \todo /// Add support for enable/disable blending per drawbuffer: glEnablei(GL_BLEND, drawBufferIndex) //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Blending::Blending() : RenderState(BLENDING), m_enableBlending(false), m_funcSourceRGB(ONE), m_funcDestinationRGB(ZERO), m_funcSourceAlpha(ONE), m_funcDestinationAlpha(ZERO), m_equationRGB(FUNC_ADD), m_equationAlpha(FUNC_ADD), m_blendColor(0, 0, 0, 0) { } //-------------------------------------------------------------------------------------------------- /// glEnable(GL_BLEND) / glDisable(GL_BLEND) //-------------------------------------------------------------------------------------------------- void Blending::enableBlending(bool blend/*, uint drawBufferIndex*/) { m_enableBlending = blend; } //-------------------------------------------------------------------------------------------------- /// glBlendFunc() //-------------------------------------------------------------------------------------------------- void Blending::setFunction(Function source, Function destination) { m_funcSourceRGB = source; m_funcSourceAlpha = source; m_funcDestinationRGB = destination; m_funcDestinationAlpha = destination; } //-------------------------------------------------------------------------------------------------- /// glBlendEquation(). Requires OpenGL 2.0 //-------------------------------------------------------------------------------------------------- void Blending::setEquation(Equation eq) { m_equationRGB = eq; m_equationAlpha = eq; } //-------------------------------------------------------------------------------------------------- /// glBlendFuncSeparate(). Requires OpenGL 2.0 //-------------------------------------------------------------------------------------------------- void Blending::setFunctionSeparate(Function sourceRGB, Function destinationRGB, Function sourceAlpha, Function destinationAlpha) { m_funcSourceRGB = sourceRGB; m_funcDestinationRGB = destinationRGB; m_funcSourceAlpha = sourceAlpha; m_funcDestinationAlpha = destinationAlpha; } //-------------------------------------------------------------------------------------------------- /// glBlendEquationSeparate(). Requires OpenGL 2.0 //-------------------------------------------------------------------------------------------------- void Blending::setEquationSeparate(Equation equationRGB, Equation equationAlpha) { m_equationRGB = equationRGB; m_equationAlpha = equationAlpha; } //-------------------------------------------------------------------------------------------------- /// glBlendColor(). Requires OpenGL 2.0 //-------------------------------------------------------------------------------------------------- void Blending::setBlendColor(Color4f blendColor) { m_blendColor = blendColor; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Blending::configureTransparencyBlending() { m_enableBlending = true; setFunction(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Blending::applyOpenGL(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); /// As we do not care about specific support for OpenGL 1.4, 1.3 etc., everything that is not in 1.1 /// will require at least support for our baseline (currently OpenGL 2.0) bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); if (m_enableBlending) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } if ((m_funcSourceRGB == m_funcSourceAlpha) && (m_funcDestinationRGB == m_funcDestinationAlpha)) { glBlendFunc(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB)); } else { if (openGL2Support) { glBlendFuncSeparate(blendFuncOpenGL(m_funcSourceRGB), blendFuncOpenGL(m_funcDestinationRGB), blendFuncOpenGL(m_funcSourceAlpha), blendFuncOpenGL(m_funcDestinationAlpha)); } else { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support separate blend functions."); } } if (openGL2Support) { if (m_equationRGB == m_equationAlpha) { glBlendEquation(blendEquationOpenGL(m_equationRGB)); } else { glBlendEquationSeparate(blendEquationOpenGL(m_equationRGB), blendEquationOpenGL(m_equationAlpha)); } glBlendColor(m_blendColor.r(), m_blendColor.g(), m_blendColor.b(), m_blendColor.a()); } else { // Only error reporting here if (m_equationRGB != FUNC_ADD || m_equationRGB != m_equationAlpha) { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend equations."); } if (m_blendColor != Color4f(0, 0, 0, 0)) { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support blend color."); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvfGLenum Blending::blendEquationOpenGL(Equation eq) const { switch (eq) { case FUNC_ADD: return GL_FUNC_ADD; case FUNC_SUBTRACT: return GL_FUNC_SUBTRACT; case FUNC_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; #ifndef CVF_OPENGL_ES case MIN: return GL_MIN; case MAX: return GL_MAX; #endif } CVF_FAIL_MSG("Unhandled blend equation"); return 0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvfGLenum Blending::blendFuncOpenGL(Function func) const { switch (func) { case ZERO: return GL_ZERO; case ONE: return GL_ONE; case SRC_COLOR: return GL_SRC_COLOR; case ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; case DST_COLOR: return GL_DST_COLOR; case ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; case SRC_ALPHA: return GL_SRC_ALPHA; case ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; case DST_ALPHA: return GL_DST_ALPHA; case ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; case CONSTANT_COLOR: return GL_CONSTANT_COLOR; case ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; case CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; case ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; case SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE; } CVF_FAIL_MSG("Unhandled blend func"); return 0; } //================================================================================================== /// /// \class cvf::ColorMask /// \ingroup Render /// /// Encapsulate OpenGL glColorMask() function. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glColorMask.xml //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- ColorMask::ColorMask(bool writeAllComponents) : RenderState(COLOR_MASK), m_writeRed(writeAllComponents), m_writeGreen(writeAllComponents), m_writeBlue(writeAllComponents), m_writeAlpha(writeAllComponents) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void ColorMask::enable(bool writeRed, bool writeGreen, bool writeBlue, bool writeAlpha) { m_writeRed = writeRed; m_writeGreen = writeGreen; m_writeBlue = writeBlue; m_writeAlpha = writeAlpha; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void ColorMask::enableWriteAllComponents(bool writeAllComponents) { m_writeRed = writeAllComponents; m_writeGreen = writeAllComponents; m_writeBlue = writeAllComponents; m_writeAlpha = writeAllComponents; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool ColorMask::isRedEnabled() const { return m_writeRed; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool ColorMask::isGreenEnabled() const { return m_writeGreen; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool ColorMask::isBlueEnabled() const { return m_writeBlue; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool ColorMask::isAlphaEnabled() const { return m_writeAlpha; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void ColorMask::applyOpenGL(OpenGLContext* oglContext) const { GLboolean writeRed = m_writeRed ? static_cast(GL_TRUE) : static_cast(GL_FALSE); GLboolean writeGreen = m_writeGreen ? static_cast(GL_TRUE) : static_cast(GL_FALSE); GLboolean writeBlue = m_writeBlue ? static_cast(GL_TRUE) : static_cast(GL_FALSE); GLboolean writeAlpha = m_writeAlpha ? static_cast(GL_TRUE) : static_cast(GL_FALSE); glColorMask(writeRed, writeGreen, writeBlue, writeAlpha); CVF_CHECK_OGL(oglContext); } //================================================================================================== /// /// \class cvf::CullFace /// \ingroup Render /// /// Encapsulate OpenGL glCullFace() and glEnable(GL_CULL_FACE) functions. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glCullFace.xml /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- CullFace::CullFace(bool enableCulling, Mode faceMode) : RenderState(CULL_FACE), m_enableCulling(enableCulling), m_faceMode(faceMode) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void CullFace::enable(bool enableCulling) { m_enableCulling = enableCulling; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool CullFace::isEnabled() const { return m_enableCulling; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void CullFace::setMode(Mode faceMode) { m_faceMode = faceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- CullFace::Mode CullFace::mode() const { return m_faceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void CullFace::applyOpenGL(OpenGLContext* oglContext) const { if (m_enableCulling) { if (m_faceMode == BACK) { glCullFace(GL_BACK); } else if (m_faceMode == FRONT) { glCullFace(GL_FRONT); } else { glCullFace(GL_FRONT_AND_BACK); } glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } CVF_CHECK_OGL(oglContext); } //================================================================================================== /// /// \class cvf::FrontFace /// \ingroup Render /// /// Encapsulate OpenGL glFrontFace() used to specify polygon winding. Used together with CullFace /// render state and the gl_FrontFacing bultin shader input variable. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glFrontFace.xml /// \sa http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FrontFacing.xml //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- FrontFace::FrontFace(Mode faceMode) : RenderState(FRONT_FACE), m_faceMode(faceMode) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void FrontFace::setMode(Mode faceMode) { m_faceMode = faceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- FrontFace::Mode FrontFace::mode() const { return m_faceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void FrontFace::applyOpenGL(OpenGLContext* oglContext) const { if (m_faceMode == CW) { glFrontFace(GL_CW); } else { glFrontFace(GL_CCW); } CVF_CHECK_OGL(oglContext); } //================================================================================================== /// /// \class cvf::Depth /// \ingroup Render /// /// Encapsulate OpenGL glEnable(GL_DEPTH_TEST), glDepthFunc() and glDepthMask() functions. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml /// /// \todo /// Add support for glDepthRange() if needed. //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Depth::Depth(bool depthTest, Function func, bool depthWrite) : RenderState(DEPTH) { m_enableDepthTest = depthTest; m_depthFunc = func; m_enableDepthWrite = depthWrite; } //-------------------------------------------------------------------------------------------------- /// Specifies the depth comparison function. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthFunc.xml //-------------------------------------------------------------------------------------------------- void Depth::setFunction(Function func) { m_depthFunc = func; } //-------------------------------------------------------------------------------------------------- /// Enable or disable depth testing and updating of the depth buffer. /// /// \param enableTest Specify true to enable testing against and updating of depth buffer. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml with GL_DEPTH_TEST /// /// From OpenGL docs: /// If enabled, do depth comparisons and update the depth buffer. Note that even if the depth buffer /// exists and the depth mask is non-zero, the depth buffer is not updated if the depth test is disabled //-------------------------------------------------------------------------------------------------- void Depth::enableDepthTest(bool enableTest) { m_enableDepthTest = enableTest; } //-------------------------------------------------------------------------------------------------- /// Enable or disable writing into the depth buffer /// /// \param enableWrite Specify true to enable writing to depth buffer, false to disable. The default is true. /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glDepthMask.xml //-------------------------------------------------------------------------------------------------- void Depth::enableDepthWrite(bool enableWrite) { m_enableDepthWrite = enableWrite; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Depth::Function Depth::function() const { return m_depthFunc; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool Depth::isDepthTestEnabled() const { return m_enableDepthTest; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool Depth::isDepthWriteEnabled() const { return m_enableDepthWrite; } //-------------------------------------------------------------------------------------------------- /// Specify the depth setting to OpenGL. //-------------------------------------------------------------------------------------------------- void Depth::applyOpenGL(OpenGLContext* oglContext) const { if (m_enableDepthTest) { GLenum depthFuncOGL = depthFuncOpenGL(); glDepthFunc(depthFuncOGL); GLboolean enableDepthWrite = m_enableDepthWrite ? static_cast(GL_TRUE) : static_cast(GL_FALSE); glDepthMask(enableDepthWrite); glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } CVF_CHECK_OGL(oglContext); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvfGLenum Depth::depthFuncOpenGL() const { switch (m_depthFunc) { case NEVER: return GL_NEVER; case LESS: return GL_LESS; case EQUAL: return GL_EQUAL; case LEQUAL: return GL_LEQUAL; case GREATER: return GL_GREATER; case NOTEQUAL: return GL_NOTEQUAL; case GEQUAL: return GL_GEQUAL; case ALWAYS: return GL_ALWAYS; } CVF_FAIL_MSG("Unhandled depth func"); return 0; } //================================================================================================== /// /// \class cvf::Point /// \ingroup Render /// /// /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Point::Point(Mode sizeMode) : RenderState(POINT), m_sizeMode(sizeMode), m_pointSprite(false), m_pointSize(1.0f) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Point::setMode(Mode sizeMode) { m_sizeMode = sizeMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Point::Mode Point::mode() const { return m_sizeMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Point::enablePointSprite(bool enable) { m_pointSprite = enable; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool Point::isPointSpriteEnabled() const { return m_pointSprite; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Point::setSize(float pointSize) { m_pointSize = pointSize; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- float Point::size() const { return m_pointSize; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void Point::applyOpenGL(OpenGLContext* oglContext) const { // OpenGL ES does not support fixed point size // Point size is always specified using GLSL's gl_PointSize #ifndef CVF_OPENGL_ES bool openGL2Support = oglContext->capabilities()->supportsOpenGL2(); if (m_sizeMode == FIXED_SIZE) { if (openGL2Support) { glDisable(GL_PROGRAM_POINT_SIZE); } glPointSize(m_pointSize); } else { if (openGL2Support) { glEnable(GL_PROGRAM_POINT_SIZE); } else { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support program point size."); } } if (openGL2Support) { if (m_pointSprite) glEnable(GL_POINT_SPRITE); else glDisable(GL_POINT_SPRITE); } else { if (m_pointSprite) { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support point sprites."); } } #endif CVF_CHECK_OGL(oglContext); } //================================================================================================== /// /// \class cvf::PolygonMode /// \ingroup Render /// /// /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- PolygonMode::PolygonMode(Mode frontAndBackFaceMode) : RenderState(POLYGON_MODE), m_frontFaceMode(frontAndBackFaceMode), m_backFaceMode(frontAndBackFaceMode) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonMode::set(Mode frontAndBackMode) { m_frontFaceMode = frontAndBackMode; m_backFaceMode = frontAndBackMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonMode::setFrontFace(Mode mode) { m_frontFaceMode = mode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonMode::setBackFace(Mode mode) { m_backFaceMode = mode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- PolygonMode::Mode PolygonMode::frontFace() const { return m_frontFaceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- PolygonMode::Mode PolygonMode::backFace() const { return m_backFaceMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonMode::applyOpenGL(OpenGLContext* oglContext) const { #ifndef CVF_OPENGL_ES if (m_frontFaceMode == m_backFaceMode) { glPolygonMode(GL_FRONT_AND_BACK, polygonModeOpenGL(m_frontFaceMode)); } else { glPolygonMode(GL_FRONT, polygonModeOpenGL(m_frontFaceMode)); glPolygonMode(GL_BACK, polygonModeOpenGL(m_backFaceMode)); } #endif CVF_CHECK_OGL(oglContext); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvfGLenum PolygonMode::polygonModeOpenGL(Mode mode) { switch (mode) { #ifndef CVF_OPENGL_ES case FILL: return GL_FILL; case LINE: return GL_LINE; case POINT: return GL_POINT; default: CVF_FAIL_MSG("Unhandled polygon mode"); #endif } return 0; } //================================================================================================== /// /// \class cvf::PolygonOffset /// \ingroup Render /// /// Encapsulate OpenGL glPolygonOffset() and glEnable()/glDisable() with GL_POLYGON_OFFSET_FILL/LINE/POINT /// /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glPolygonOffset.xml /// \sa http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml /// //================================================================================================== PolygonOffset::PolygonOffset() : RenderState(POLYGON_OFFSET), m_factor(0.0f), m_units(0.0f), m_enableFillMode(false), m_enableLineMode(false), m_enablePointMode(false) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::enableFillMode(bool enableFill) { m_enableFillMode = enableFill; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::enableLineMode(bool enableLine) { m_enableLineMode = enableLine; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::enablePointMode(bool enablePoint) { m_enablePointMode = enablePoint; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool PolygonOffset::isFillModeEnabled() const { return m_enableFillMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool PolygonOffset::isLineModeEnabled() const { return m_enableLineMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool PolygonOffset::isPointModeEnabled() const { return m_enablePointMode; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::setFactor(float factor) { m_factor = factor; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::setUnits(float units) { m_units = units; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- float PolygonOffset::factor() const { return m_factor; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- float PolygonOffset::units() const { return m_units; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::configurePolygonPositiveOffset() { m_enableFillMode = true; m_enableLineMode = false; m_enablePointMode = false; m_factor = 1.0; m_units = 1.0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::configureLineNegativeOffset() { m_enableFillMode = false; m_enableLineMode = true; m_enablePointMode = false; m_factor = -1.0; m_units = -1.0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void PolygonOffset::applyOpenGL(OpenGLContext* oglContext) const { if (m_enableFillMode || m_enableLineMode || m_enablePointMode) { glPolygonOffset(m_factor, m_units); } if (m_enableFillMode) glEnable(GL_POLYGON_OFFSET_FILL); else glDisable(GL_POLYGON_OFFSET_FILL); #ifndef CVF_OPENGL_ES if (m_enableLineMode) glEnable(GL_POLYGON_OFFSET_LINE); else glDisable(GL_POLYGON_OFFSET_LINE); if (m_enablePointMode) glEnable(GL_POLYGON_OFFSET_POINT); else glDisable(GL_POLYGON_OFFSET_POINT); #endif CVF_CHECK_OGL(oglContext); } //================================================================================================== /// /// \class cvf::TextureBindings /// \ingroup Render /// /// \warning Requires OpenGL2 support /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- TextureBindings::TextureBindings() : RenderState(TEXTURE_BINDINGS), m_bindingCount(0) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- TextureBindings::TextureBindings(Texture* texture, Sampler* sampler, const char* samplerUniformName) : RenderState(TEXTURE_BINDINGS), m_bindingCount(0) { addBinding(texture, sampler, samplerUniformName); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- TextureBindings::~TextureBindings() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void TextureBindings::addBinding(Texture* texture, Sampler* sampler, const char* samplerUniformName) { CVF_ASSERT(m_bindingCount < MAX_TEXTURE_UNITS - 1); CVF_ASSERT(texture && sampler && samplerUniformName); m_bindings[m_bindingCount].sampler = sampler; m_bindings[m_bindingCount].texture = texture; m_bindings[m_bindingCount].samplerUniformName = samplerUniformName; m_bindingCount++; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int TextureBindings::bindingCount() const { return m_bindingCount; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Texture* TextureBindings::texture(int bindingIdx) { CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); return m_bindings[bindingIdx].texture.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const Texture* TextureBindings::texture(int bindingIdx) const { CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); return m_bindings[bindingIdx].texture.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const Sampler* TextureBindings::sampler(int bindingIdx) const { CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); return m_bindings[bindingIdx].sampler.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- Sampler* TextureBindings::sampler(int bindingIdx) { CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); return m_bindings[bindingIdx].sampler.p(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- String TextureBindings::samplerUniformName(int bindingIdx) const { CVF_ASSERT(bindingIdx >= 0 && bindingIdx < m_bindingCount); return m_bindings[bindingIdx].samplerUniformName; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void TextureBindings::setupTextures(OpenGLContext* oglContext) { CVF_CALLSITE_OPENGL(oglContext); const OpenGLCapabilities* oglCaps = oglContext->capabilities(); if (!oglCaps->supportsOpenGL2()) { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support texture setup using TextureBindings."); return; } glActiveTexture(GL_TEXTURE0); int i; for (i = 0; i < m_bindingCount; i++) { Texture* texture = m_bindings[i].texture.p(); if (texture->textureOglId() == 0) { glActiveTexture(static_cast(GL_TEXTURE0 + i)); texture->setupTexture(oglContext); CVF_CHECK_OGL(oglContext); } else { // Handle case where mipmap generation is enabled, but the mipmaps are not present // This will typically happen if the texture has been rendered to using an FBO // In that case the texture exists, but no mipmaps have yet been generated if (texture->isMipmapGenerationEnabled() && !texture->hasMipmap()) { if (oglCaps->hasCapability(OpenGLCapabilities::GENERATE_MIPMAP_FUNC)) { glActiveTexture(static_cast(GL_TEXTURE0 + i)); texture->generateMipmap(oglContext); CVF_CHECK_OGL(oglContext); } else { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support explicit mipmap generation."); } } } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void TextureBindings::applyOpenGL(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); // The apply function needs to work for all contexts in its default state // so just return if no bindings have been set if (m_bindingCount == 0) { return; } if (!oglContext->capabilities()->supportsOpenGL2()) { CVF_LOG_RENDER_ERROR(oglContext, "Context does not support TextureBinding application."); return; } int i; for (i = 0; i < m_bindingCount; i++) { const Texture* texture = m_bindings[i].texture.p(); const Sampler* sampler = m_bindings[i].sampler.p(); CVF_ASSERT(texture && sampler); glActiveTexture(static_cast(GL_TEXTURE0 + i)); texture->bind(oglContext); texture->setupTextureParamsFromSampler(oglContext, *sampler); CVF_CHECK_OGL(oglContext); } } //-------------------------------------------------------------------------------------------------- /// Specify the mapping between the sampler name in the shader program and the texture unit /// This is done by providing an Int Uniform with the name of the sampler and the index of the /// texture unit. //-------------------------------------------------------------------------------------------------- void TextureBindings::applySamplerTextureUnitUniforms(OpenGLContext* oglContext, ShaderProgram* shaderProgram) const { CVF_ASSERT(shaderProgram); int i; for (i = 0; i < m_bindingCount; i++) { UniformInt uniform(m_bindings[i].samplerUniformName.toAscii().ptr(), i); shaderProgram->applyUniform(oglContext, uniform); } } } // namespace cvf