//-------------------------------------------------------------------------------------------------- /// Draw a background rectangle using OGL 1.1 compatibility //-------------------------------------------------------------------------------------------------- void InternalLegendRenderTools::renderBackgroundImmediateMode(OpenGLContext* oglContext, const Vec2f& size, const Color4f& backgroundColor, const Color4f& backgroundFrameColor) { RenderStateDepth depth(false); depth.applyOpenGL(oglContext); RenderStateLighting_FF lighting(false); lighting.applyOpenGL(oglContext); RenderStateBlending blend; blend.configureTransparencyBlending(); blend.applyOpenGL(oglContext); // Frame vertices std::array<Vec3f, 4> vertexArray = { Vec3f(1 , 1, 0.0f), Vec3f(size.x(), 1, 0.0f), Vec3f(size.x(), size.y(), 0.0f), Vec3f(1 , size.y(), 0.0f), }; glColor4fv(backgroundColor.ptr()); glBegin(GL_TRIANGLE_FAN); glVertex3fv(vertexArray[0].ptr()); glVertex3fv(vertexArray[1].ptr()); glVertex3fv(vertexArray[2].ptr()); glVertex3fv(vertexArray[3].ptr()); glEnd(); // Render Line around { glColor4fv(backgroundFrameColor.ptr()); glBegin(GL_LINES); glVertex3fv(vertexArray[0].ptr()); glVertex3fv(vertexArray[1].ptr()); glVertex3fv(vertexArray[1].ptr()); glVertex3fv(vertexArray[2].ptr()); glVertex3fv(vertexArray[2].ptr()); glVertex3fv(vertexArray[3].ptr()); glVertex3fv(vertexArray[3].ptr()); glVertex3fv(vertexArray[0].ptr()); glEnd(); } // Reset render states RenderStateLighting_FF resetLighting; resetLighting.applyOpenGL(oglContext); RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); RenderStateBlending resetblend; resetblend.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void OverlayImage::render(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size, bool software) { CVF_CALLSITE_OPENGL(oglContext); Camera projCam; projCam.setViewport(position.x(), position.y(), size.x(), size.y()); projCam.setProjectionAsPixelExact2D(); projCam.setViewMatrix(Mat4d::IDENTITY); // Turn off depth test RenderStateDepth depth(false, RenderStateDepth::LESS, false); depth.applyOpenGL(oglContext); float vertexArray[12]; float textureCoords[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; projCam.viewport()->applyOpenGL(oglContext, Viewport::DO_NOT_CLEAR); if (software) { // Create a POW2 texture for software rendering if needed if (m_image.notNull() && m_pow2Image.isNull() && (!Math::isPow2(m_image->width()) || !Math::isPow2(m_image->height()))) { m_pow2Image = new TextureImage; m_pow2Image->allocate(Math::roundUpPow2(m_image->width()), Math::roundUpPow2(m_image->height())); m_pow2Image->fill(Color4ub(Color3::BLACK)); for (uint y = 0; y < m_image->height(); ++y) { for (uint x = 0; x < m_image->width(); ++x) { m_pow2Image->setPixel(x, y, m_image->pixel(x, y)); } } } if (ShaderProgram::supportedOpenGL(oglContext)) { ShaderProgram::useNoProgram(oglContext); } #ifndef CVF_OPENGL_ES RenderStateMaterial_FF mat; mat.enableColorMaterial(true); mat.applyOpenGL(oglContext); RenderStateLighting_FF light(false); light.applyOpenGL(oglContext); if (m_textureBindings.isNull()) { // Use fixed function texture setup ref<Texture2D_FF> texture = new Texture2D_FF(m_pow2Image.notNull() ? m_pow2Image.p() : m_image.p()); texture->setWrapMode(Texture2D_FF::CLAMP); texture->setMinFilter(Texture2D_FF::NEAREST); texture->setMagFilter(Texture2D_FF::NEAREST); texture->setupTexture(oglContext); texture->setupTextureParams(oglContext); ref<RenderStateTextureMapping_FF> textureMapping = new RenderStateTextureMapping_FF(texture.p()); textureMapping->setTextureFunction(m_blendMode == TEXTURE_ALPHA ? RenderStateTextureMapping_FF::MODULATE : RenderStateTextureMapping_FF::DECAL); m_textureBindings = textureMapping; } #endif // Adjust texture coordinates if (m_pow2Image.notNull()) { float xMax = static_cast<float>(m_image->width())/static_cast<float>(m_pow2Image->width()); float yMax = static_cast<float>(m_image->height())/static_cast<float>(m_pow2Image->height()); textureCoords[2] = xMax; textureCoords[4] = xMax; textureCoords[5] = yMax; textureCoords[7] = yMax; } projCam.applyOpenGL(); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableVertexAttribArray(ShaderProgram::VERTEX); glEnableVertexAttribArray(ShaderProgram::TEX_COORD_2F_0); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); glVertexAttribPointer(ShaderProgram::TEX_COORD_2F_0, 2, GL_FLOAT, GL_FALSE, 0, textureCoords); if (m_shaderProgram.isNull()) { ShaderProgramGenerator gen("OverlayImage_Shader", ShaderSourceProvider::instance()); gen.addVertexCode(ShaderSourceRepository::vs_MinimalTexture); if (m_blendMode == GLOBAL_ALPHA) { gen.addFragmentCode(ShaderSourceRepository::src_TextureGlobalAlpha); } else { gen.addFragmentCode(ShaderSourceRepository::src_Texture); } gen.addFragmentCode(ShaderSourceRepository::fs_Unlit); m_shaderProgram = gen.generate(); m_shaderProgram->linkProgram(oglContext); } if (m_shaderProgram->useProgram(oglContext)) { MatrixState projMatrixState(projCam); m_shaderProgram->clearUniformApplyTracking(); m_shaderProgram->applyFixedUniforms(oglContext, projMatrixState); } if (m_texture->textureOglId() == 0) { m_texture->setupTexture(oglContext); } if (m_textureBindings.isNull()) { cvf::RenderStateTextureBindings* textureBindings = new cvf::RenderStateTextureBindings; textureBindings->addBinding(m_texture.p(), m_sampler.p(), "u_texture2D"); m_textureBindings = textureBindings; } } float offset = 0.0f; Vec3f min(offset, offset, 0.0f); Vec3f max(static_cast<float>(size.x()) + offset, static_cast<float>(size.y()) + offset, 0.0f); // Setup the vertex array float* v1 = &vertexArray[0]; float* v2 = &vertexArray[3]; float* v3 = &vertexArray[6]; float* v4 = &vertexArray[9]; v1[0] = min.x(); v1[1] = min.y(); v1[2] = 0.0f; v2[0] = max.x(); v2[1] = min.y(); v2[2] = 0.0f; v3[0] = max.x(); v3[1] = max.y(); v3[2] = 0.0f; v4[0] = min.x(); v4[1] = max.y(); v4[2] = 0.0f; if (m_blendMode != NO_BLENDING) { RenderStateBlending blend; blend.configureTransparencyBlending(); blend.applyOpenGL(oglContext); } m_textureBindings->applyOpenGL(oglContext); if (software) { #ifndef CVF_OPENGL_ES glColor4f(1.0f, 1.0f, 1.0f, m_blendMode == GLOBAL_ALPHA ? m_alpha : 1.0f); glBegin(GL_TRIANGLE_FAN); glTexCoord2f(textureCoords[0], textureCoords[1]); glVertex3fv(v1); glTexCoord2f(textureCoords[2], textureCoords[3]); glVertex3fv(v2); glTexCoord2f(textureCoords[4], textureCoords[5]); glVertex3fv(v3); glTexCoord2f(textureCoords[6], textureCoords[7]); glVertex3fv(v4); glEnd(); #endif } else { if (m_blendMode == GLOBAL_ALPHA) { UniformFloat alphaUniform("u_alpha", m_alpha); m_shaderProgram->applyUniform(oglContext, alphaUniform); } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } if (m_blendMode != NO_BLENDING) { RenderStateBlending blend; blend.applyOpenGL(oglContext); } RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); if (software) { #ifndef CVF_OPENGL_ES RenderStateTextureMapping_FF resetTextureMapping; resetTextureMapping.applyOpenGL(oglContext); #endif } if (!software) { glDisableVertexAttribArray(ShaderProgram::VERTEX); glDisableVertexAttribArray(ShaderProgram::TEX_COORD_2F_0); } }
//-------------------------------------------------------------------------------------------------- /// Render a semi transparent background frame //-------------------------------------------------------------------------------------------------- void InternalLegendRenderTools::renderBackgroundUsingShaders(OpenGLContext* oglContext, const MatrixState& matrixState, const Vec2f& size, const Color4f& backgroundColor, const Color4f& backgroundFrameColor) { CVF_CALLSITE_OPENGL(oglContext); RenderStateDepth depth(false); depth.applyOpenGL(oglContext); RenderStateLine line(1.0f); line.applyOpenGL(oglContext); RenderStateBlending blend; blend.configureTransparencyBlending(); blend.applyOpenGL(oglContext); // Shader program ref<ShaderProgram> shaderProgram = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); CVF_TIGHT_ASSERT(shaderProgram.notNull()); if (shaderProgram->useProgram(oglContext)) { shaderProgram->clearUniformApplyTracking(); shaderProgram->applyFixedUniforms(oglContext, matrixState); } std::array<Vec3f, 4> vertexArray ={ Vec3f(1 , 1, 0.0f), Vec3f(size.x(), 1, 0.0f), Vec3f(size.x(), size.y(), 0.0f), Vec3f(1 , size.y(), 0.0f), }; glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableVertexAttribArray(ShaderProgram::VERTEX); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray.data()); // Draw frame background UniformFloat backgroundColorUniform("u_color", backgroundColor); shaderProgram->applyUniform(oglContext, backgroundColorUniform); // Triangle indices for the frame background static const ushort backgroundTriangleIndices[] = { 0, 1, 2, 2, 3, 0}; glDrawRangeElements(GL_TRIANGLES, 0, 3, 6, GL_UNSIGNED_SHORT, backgroundTriangleIndices); // Draw frame border lines UniformFloat uniformColor("u_color", backgroundFrameColor); shaderProgram->applyUniform(oglContext, uniformColor); static const ushort frameLineIndices[] = { 0, 1, 1, 2, 2, 3, 3, 0 }; glDrawRangeElements(GL_LINES, 0, 3, 8, GL_UNSIGNED_SHORT, frameLineIndices); glDisableVertexAttribArray(ShaderProgram::VERTEX); CVF_TIGHT_ASSERT(shaderProgram.notNull()); shaderProgram->useNoProgram(oglContext); // Reset render states RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); RenderStateLine resetLine; resetLine.applyOpenGL(oglContext); RenderStateBlending resetblend; resetblend.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// Draw the legend using immediate mode OpenGL //-------------------------------------------------------------------------------------------------- void OverlayScalarMapperLegend::renderLegendImmediateMode(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout) { #ifdef CVF_OPENGL_ES CVF_UNUSED(layout); CVF_FAIL_MSG("Not supported on OpenGL ES"); #else CVF_TIGHT_ASSERT(layout); CVF_TIGHT_ASSERT(layout->size.x() > 0); CVF_TIGHT_ASSERT(layout->size.y() > 0); RenderStateDepth depth(false); depth.applyOpenGL(oglContext); RenderStateLighting_FF lighting(false); lighting.applyOpenGL(oglContext); // All vertices. Initialized here to set Z to zero once and for all. static float vertexArray[] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; // Per vector convenience pointers float* v0 = &vertexArray[0]; float* v1 = &vertexArray[3]; float* v2 = &vertexArray[6]; float* v3 = &vertexArray[9]; float* v4 = &vertexArray[12]; // Constant coordinates v0[0] = v3[0] = layout->x0; v1[0] = v4[0] = layout->x1; // Render color bar as one colored quad per pixel int legendHeightPixelCount = static_cast<int>(layout->tickPixelPos->get(m_tickValues.size() - 1) - layout->tickPixelPos->get(0) + 0.01); if (m_scalarMapper.notNull()) { int iPx; for (iPx = 0; iPx < legendHeightPixelCount; iPx++) { const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); float y0 = static_cast<float>(layout->legendRect.min().y() + iPx); float y1 = static_cast<float>(layout->legendRect.min().y() + iPx + 1); // Dynamic coordinates for rectangle v0[1] = v1[1] = y0; v3[1] = v4[1] = y1; // Draw filled rectangle elements glColor3ubv(clr.ptr()); glBegin(GL_TRIANGLE_FAN); glVertex3fv(v0); glVertex3fv(v1); glVertex3fv(v4); glVertex3fv(v3); glEnd(); } } // Render frame // Dynamic coordinates for tickmarks-lines bool isRenderingFrame = true; if (isRenderingFrame) { v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; glColor3fv(m_color.ptr()); glBegin(GL_LINES); glVertex3fv(v0); glVertex3fv(v1); glVertex3fv(v1); glVertex3fv(v3); glVertex3fv(v3); glVertex3fv(v2); glVertex3fv(v2); glVertex3fv(v0); glEnd(); } // Render tickmarks bool isRenderingTicks = true; if (isRenderingTicks) { // Constant coordinates v0[0] = layout->x0; v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; v2[0] = layout->x1; v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; v4[0] = layout->tickX; size_t ic; for (ic = 0; ic < m_tickValues.size(); ic++) { float y0 = static_cast<float>(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); // Dynamic coordinates for tickmarks-lines v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; glColor3fv(m_color.ptr()); glBegin(GL_LINES); if ( m_visibleTickLabels[ic]) { glVertex3fv(v0); glVertex3fv(v4); } else { glVertex3fv(v2); glVertex3fv(v3); } glEnd(); } } // Reset render states RenderStateLighting_FF resetLighting; resetLighting.applyOpenGL(oglContext); RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); #endif // CVF_OPENGL_ES }
//-------------------------------------------------------------------------------------------------- /// Draw the legend using shader programs //-------------------------------------------------------------------------------------------------- void OverlayScalarMapperLegend::renderLegend(OpenGLContext* oglContext, OverlayColorLegendLayoutInfo* layout, const MatrixState& matrixState) { CVF_CALLSITE_OPENGL(oglContext); CVF_TIGHT_ASSERT(layout); CVF_TIGHT_ASSERT(layout->size.x() > 0); CVF_TIGHT_ASSERT(layout->size.y() > 0); RenderStateDepth depth(false); depth.applyOpenGL(oglContext); RenderStateLine line(static_cast<float>(m_lineWidth)); line.applyOpenGL(oglContext); // All vertices. Initialized here to set Z to zero once and for all. static float vertexArray[] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; // Per vector convenience pointers float* v0 = &vertexArray[0]; float* v1 = &vertexArray[3]; float* v2 = &vertexArray[6]; float* v3 = &vertexArray[9]; float* v4 = &vertexArray[12]; // Constant coordinates v0[0] = v3[0] = layout->x0; v1[0] = v4[0] = layout->x1; // Connects static const ushort trianglesConnects[] = { 0, 1, 4, 0, 4, 3 }; ref<ShaderProgram> shaderProgram = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); CVF_TIGHT_ASSERT(shaderProgram.notNull()); if (shaderProgram->useProgram(oglContext)) { shaderProgram->clearUniformApplyTracking(); shaderProgram->applyFixedUniforms(oglContext, matrixState); } glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableVertexAttribArray(ShaderProgram::VERTEX); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); // Render color bar as one colored quad per pixel int legendHeightPixelCount = static_cast<int>(layout->tickPixelPos->get(m_tickValues.size()-1) - layout->tickPixelPos->get(0) + 0.01); if (m_scalarMapper.notNull()) { int iPx; for (iPx = 0; iPx < legendHeightPixelCount; iPx++) { const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); float y0 = static_cast<float>(layout->legendRect.min().y() + iPx); float y1 = static_cast<float>(layout->legendRect.min().y() + iPx + 1); // Dynamic coordinates for rectangle v0[1] = v1[1] = y0; v3[1] = v4[1] = y1; // Draw filled rectangle elements { UniformFloat uniformColor("u_color", Color4f(Color3f(clr))); shaderProgram->applyUniform(oglContext, uniformColor); #ifdef CVF_OPENGL_ES glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, trianglesConnects); #else glDrawRangeElements(GL_TRIANGLES, 0, 4, 6, GL_UNSIGNED_SHORT, trianglesConnects); #endif } } } // Render frame // Dynamic coordinates for tickmarks-lines bool isRenderingFrame = true; if (isRenderingFrame) { v0[0] = v2[0] = layout->legendRect.min().x()-0.5f; v1[0] = v3[0] = layout->legendRect.max().x()-0.5f; v0[1] = v1[1] = layout->legendRect.min().y()-0.5f; v2[1] = v3[1] = layout->legendRect.max().y()-0.5f; static const ushort frameConnects[] = { 0, 1, 1, 3, 3, 2, 2, 0}; UniformFloat uniformColor("u_color", Color4f(m_lineColor)); shaderProgram->applyUniform(oglContext, uniformColor); #ifdef CVF_OPENGL_ES glDrawElements(GL_LINES, 8, GL_UNSIGNED_SHORT, frameConnects); #else glDrawRangeElements(GL_LINES, 0, 3, 8, GL_UNSIGNED_SHORT, frameConnects); #endif } // Render tickmarks bool isRenderingTicks = true; if (isRenderingTicks) { // Constant coordinates v0[0] = layout->x0; v1[0] = layout->x1 - 0.5f*(layout->tickX - layout->x1) - 0.5f; v2[0] = layout->x1; v3[0] = layout->tickX - 0.5f*(layout->tickX - layout->x1) - 0.5f; v4[0] = layout->tickX; static const ushort tickLinesWithLabel[] = { 0, 4 }; static const ushort tickLinesWoLabel[] = { 2, 3 }; size_t ic; for (ic = 0; ic < m_tickValues.size(); ic++) { float y0 = static_cast<float>(layout->legendRect.min().y() + layout->tickPixelPos->get(ic) - 0.5f); // Dynamic coordinates for tickmarks-lines v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; UniformFloat uniformColor("u_color", Color4f(m_lineColor)); shaderProgram->applyUniform(oglContext, uniformColor); const ushort * linesConnects; if ( m_visibleTickLabels[ic]) { linesConnects = tickLinesWithLabel; } else { linesConnects = tickLinesWoLabel; } #ifdef CVF_OPENGL_ES glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, linesConnects); #else glDrawRangeElements(GL_LINES, 0, 4, 2, GL_UNSIGNED_SHORT, linesConnects); #endif } } glDisableVertexAttribArray(ShaderProgram::VERTEX); CVF_TIGHT_ASSERT(shaderProgram.notNull()); shaderProgram->useNoProgram(oglContext); // Reset render states RenderStateDepth resetDepth; resetDepth.applyOpenGL(oglContext); RenderStateLine resetLine; resetLine.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); }