//-------------------------------------------------------------------------------------------------- /// Render primitives in this primitive set using vertex arrays /// /// \warning Requires at least OpenGL 1.5 //-------------------------------------------------------------------------------------------------- void PrimitiveSetIndexedUShort::render(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); CVF_TIGHT_ASSERT(BufferObjectManaged::supportedOpenGL(oglContext)); if (m_indices.isNull()) { return; } GLsizei numIndices = static_cast<GLsizei>(m_indices->size()); if (numIndices <= 0) { return; } const GLvoid* ptrOrOffset = 0; if (m_indicesBO.notNull() && m_indicesBO->isUploaded()) { m_indicesBO->bindBuffer(oglContext); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ptrOrOffset = m_indices->ptr(); } #ifdef CVF_OPENGL_ES glDrawElements(primitiveTypeOpenGL(), numIndices, GL_UNSIGNED_SHORT, ptrOrOffset); #else glDrawRangeElements(primitiveTypeOpenGL(), m_minIndex, m_maxIndex, numIndices, GL_UNSIGNED_SHORT, ptrOrOffset); #endif }
//-------------------------------------------------------------------------------------------------- /// Render primitives in this primitive set using vertex arrays /// /// \warning Requires at least OpenGL 1.5 //-------------------------------------------------------------------------------------------------- void PrimitiveSetIndexedUShortScoped::render(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); CVF_ASSERT(BufferObjectManaged::supportedOpenGL(oglContext)); if (m_indices.isNull()) { return; } GLsizei numIndices = static_cast<GLsizei>(m_elementCount); if (numIndices <= 0) { return; } const GLvoid* ptrOrOffset = 0; if (m_indicesBO.notNull() && m_indicesBO->isUploaded()) { m_indicesBO->bindBuffer(oglContext); ptrOrOffset = reinterpret_cast<GLvoid*>(m_firstElement*sizeof(GLushort)); } else { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ptrOrOffset = m_indices->ptr() + m_firstElement; } glDrawElements(primitiveTypeOpenGL(), numIndices, GL_UNSIGNED_SHORT, ptrOrOffset); CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RenderStateTextureMapping_FF::applyOpenGL(OpenGLContext* oglContext) const { CVF_CALLSITE_OPENGL(oglContext); if (oglContext->capabilities()->supportsOpenGL2()) { glActiveTexture(GL_TEXTURE0); } if (m_texture.notNull() && m_texture->textureOglId() != 0) { m_texture->bind(oglContext); m_texture->setupTextureParams(oglContext); cvfGLint oglTexFunc = GL_MODULATE; switch (m_textureFunction) { case MODULATE: oglTexFunc = GL_MODULATE; break; case DECAL: oglTexFunc = GL_DECAL; break; } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, oglTexFunc); glEnable(GL_TEXTURE_2D); if (m_environmentMapping) { glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); GLint piSphereMap[1]; piSphereMap[0] = GL_SPHERE_MAP; glTexGeniv(GL_S, GL_TEXTURE_GEN_MODE, piSphereMap); glTexGeniv(GL_T, GL_TEXTURE_GEN_MODE, piSphereMap); } else { glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); } } else { glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); } CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RenderStateTextureMapping_FF::setupTexture(OpenGLContext* oglContext) { CVF_CALLSITE_OPENGL(oglContext); if (m_texture.notNull()) { if (m_texture->textureOglId() == 0) { if (oglContext->capabilities()->supportsOpenGL2()) { glActiveTexture(GL_TEXTURE0); } m_texture->setupTexture(oglContext); CVF_CHECK_OGL(oglContext); } } }
//-------------------------------------------------------------------------------------------------- /// Explicitly generate mipmaps /// /// \warning Requires the GENERATE_MIPMAP_FUNC capability. Will assert if this requirement is not met. //-------------------------------------------------------------------------------------------------- void Texture::generateMipmap(OpenGLContext* oglContext) { CVF_CALLSITE_OPENGL(oglContext); CVF_ASSERT(oglContext->capabilities()->hasCapability(OpenGLCapabilities::GENERATE_MIPMAP_FUNC)); bind(oglContext); if (m_textureType == TEXTURE_2D) { glGenerateMipmap(GL_TEXTURE_2D); m_hasMipmaps = true; } else if (m_textureType == TEXTURE_CUBE_MAP) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); m_hasMipmaps = true; } else { CVF_FAIL_MSG("Mipmap generation not supported for this texture type"); } CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void DrawableVectors::render(OpenGLContext* oglContext, ShaderProgram* shaderProgram, const MatrixState&) { CVF_CALLSITE_OPENGL(oglContext); CVF_ASSERT(shaderProgram); CVF_ASSERT(shaderProgram->isProgramUsed(oglContext)); CVF_ASSERT(m_vertexArray->size() == m_vectorArray->size()); CVF_ASSERT(m_colorArray.isNull() || (m_colorArray->size() == m_vectorArray->size())); CVF_ASSERT(m_vectorGlyph.notNull()); CVF_ASSERT(m_vectorGlyph->primitiveSetCount() == 1); // Setup Vertex Arrays/vbos const GLvoid* ptrOrOffset = 0; if (m_renderWithVBO && m_glyphVerticesAndNormalsBO.notNull() && m_glyphVerticesAndNormalsBO->isUploaded()) { // Bind VBO for vertex and normal data m_glyphVerticesAndNormalsBO->bindBuffer(oglContext); glVertexAttribPointer(ShaderProgram::NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(float)*6, (void*)(sizeof(float)*3)); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(float)*6, 0); glEnableVertexAttribArray(ShaderProgram::NORMAL); glEnableVertexAttribArray(ShaderProgram::VERTEX); m_indicesBO->bindBuffer(oglContext); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribPointer(ShaderProgram::NORMAL, 3, GL_FLOAT, GL_FALSE, 0, m_vectorGlyph->normalArray()->ptr()->ptr()); glEnableVertexAttribArray(ShaderProgram::NORMAL); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, m_vectorGlyph->vertexArray()->ptr()->ptr()); glEnableVertexAttribArray(ShaderProgram::VERTEX); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ptrOrOffset = m_vectorGlyphPrimSet->indices()->ptr(); } // Must use manual uniform setting, as setting the uniform through the Uniform* class requires a lookup for location // every time, and this is always the same GLint vectorMatrixUniformLocation = shaderProgram->uniformLocation(m_vectorMatrixUniformName.toAscii().ptr()); CVF_ASSERT(vectorMatrixUniformLocation != -1); GLint colorUniformLocation = shaderProgram->uniformLocation(m_colorUniformName.toAscii().ptr()); CVF_ASSERT(colorUniformLocation != -1); #ifndef CVF_OPENGL_ES uint minIndex = m_vectorGlyphPrimSet->minIndex(); uint maxIndex = m_vectorGlyphPrimSet->maxIndex(); #endif GLsizei indexCount = static_cast<GLsizei>(m_vectorGlyphPrimSet->indexCount()); // Set the single color to use if (m_colorArray.isNull()) { glUniform3fv(colorUniformLocation, 1, m_singleColor.ptr()); } float vectorMat[16]; size_t numVectors = m_vectorArray->size(); size_t i; for (i = 0; i < numVectors; i++) { // Compute the transformation matrix vectorMatrix(i, vectorMat); // Set this as a uniform to the shader program glUniformMatrix4fv(vectorMatrixUniformLocation, 1, GL_FALSE, vectorMat); if (m_colorArray.notNull()) { glUniform3fv(colorUniformLocation, 1, m_colorArray->get(i).ptr()); } // Draw the arrow #ifdef CVF_OPENGL_ES glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, ptrOrOffset); #else glDrawRangeElements(GL_TRIANGLES, minIndex, maxIndex, indexCount, GL_UNSIGNED_SHORT, ptrOrOffset); #endif } // Cleanup glDisableVertexAttribArray(ShaderProgram::VERTEX); glDisableVertexAttribArray(ShaderProgram::NORMAL); CVF_CHECK_OGL(oglContext); // Things to consider for performance: // 1) Uniform arrays evt. Uniform buffer objects // 2) Texture // 3) Texture array // GL_ARB_draw_instanced(); // glDrawElementsInstanced }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RenderStateBlending::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."); } } }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- 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); } }
//-------------------------------------------------------------------------------------------------- /// Draw the legend using shader programs //-------------------------------------------------------------------------------------------------- void OverlayColorLegend::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); Depth depth(false); depth.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_color)); 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_color)); 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 Depth resetDepth; resetDepth.applyOpenGL(oglContext); CVF_CHECK_OGL(oglContext); }
//-------------------------------------------------------------------------------------------------- /// Do setup of the texture /// /// \warning Requires at least OpenGL2 capability. Will assert if this condition is not met. /// \warning Default unpack alignment (GL_UNPACK_ALIGNMENT) is 4 and 4 byte values is preferred, thus /// we should always use RGBA when having byte textures as GPUs are optimized to 32 bit values //-------------------------------------------------------------------------------------------------- bool Texture::setupTexture(OpenGLContext* oglContext) { CVF_CALLSITE_OPENGL(oglContext); CVF_ASSERT(OglRc::safeOglId(m_oglRcTexture.p()) == 0); const OpenGLCapabilities* oglCaps = oglContext->capabilities(); CVF_ASSERT(oglCaps->supportsOpenGL2()); CVF_CLEAR_OGL_ERROR(oglContext); // Is manual generation of mipmaps through glGenerateMipmap() supported? bool supportsGenerateMipmapFunc = oglCaps->hasCapability(OpenGLCapabilities::GENERATE_MIPMAP_FUNC); m_hasMipmaps = false; m_oglRcTexture = oglContext->resourceManager()->createOglRcTexture(oglContext); bind(oglContext); CVF_ASSERT(m_image.isNull() || (m_image->width() == m_width && m_image->height() == m_height)); switch (m_textureType) { case TEXTURE_2D: { if (m_internalFormat == DEPTH_COMPONENT16 || m_internalFormat == DEPTH_COMPONENT24 || m_internalFormat == DEPTH_COMPONENT32) { CVF_ASSERT(m_image.isNull()); CVF_ASSERT(!m_enableMipmapGeneration); glTexImage2D(GL_TEXTURE_2D, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); } else if (m_internalFormat == DEPTH24_STENCIL8) { #ifndef CVF_OPENGL_ES CVF_ASSERT(m_image.isNull()); CVF_ASSERT(!m_enableMipmapGeneration); glTexImage2D(GL_TEXTURE_2D, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); #else CVF_FAIL_MSG("Not supported on IOS"); #endif } else { #ifndef CVF_OPENGL_ES if (!supportsGenerateMipmapFunc) { // Explicit mipmap generation not supported so must configure before specifying texture image if (m_enableMipmapGeneration && m_image.notNull()) { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); m_hasMipmaps = true; } else { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); } } #endif glTexImage2D(GL_TEXTURE_2D, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_RGBA, GL_UNSIGNED_BYTE, m_image.notNull() ? m_image->ptr() : 0); if (supportsGenerateMipmapFunc && m_enableMipmapGeneration && m_image.notNull()) { glGenerateMipmap(GL_TEXTURE_2D); m_hasMipmaps = true; } } break; } case TEXTURE_RECTANGLE: { #ifndef CVF_OPENGL_ES CVF_ASSERT(!m_enableMipmapGeneration); if (m_internalFormat == DEPTH_COMPONENT16 || m_internalFormat == DEPTH_COMPONENT24 || m_internalFormat == DEPTH_COMPONENT32) { CVF_ASSERT(m_image.isNull()); glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); } else { glTexImage2D(GL_TEXTURE_RECTANGLE, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_RGBA, GL_UNSIGNED_BYTE, m_image.notNull() ? m_image->ptr() : 0); } #else CVF_FAIL_MSG("Not supported on iOS"); #endif break; } case TEXTURE_CUBE_MAP: { if (m_cubeMapImages.size() == 0) { uint i; for (i = 0; i < 6; i++) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); } } else { #ifndef CVF_OPENGL_ES if (!supportsGenerateMipmapFunc) { if (m_enableMipmapGeneration) { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE); m_hasMipmaps = true; } else { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_FALSE); } } #endif CVF_ASSERT(m_cubeMapImages.size() == 6); uint i; for (i = 0; i < 6; i++) { ref<TextureImage> img = m_cubeMapImages[i]; CVF_ASSERT(img.notNull()); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormatOpenGL(), static_cast<GLsizei>(m_width), static_cast<GLsizei>(m_height), 0, GL_RGBA, GL_UNSIGNED_BYTE, img->ptr()); } if (supportsGenerateMipmapFunc && m_enableMipmapGeneration) { glGenerateMipmap(GL_TEXTURE_CUBE_MAP); m_hasMipmaps = true; } } break; } } if (CVF_TEST_AND_REPORT_OPENGL_ERROR(oglContext, "Setup texture")) { deleteTexture(oglContext); return false; } m_versionTick++; return true; }
//-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void OverlayTextBox::renderBackgroundAndBorder(OpenGLContext* oglContext, const Vec2ui& position, const Vec2ui& size, bool software) { CVF_CALLSITE_OPENGL(oglContext); // Prepare 2D pixel exact projection to draw texts 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); ref<ShaderProgram> backgroundShader; float vertexArray[12]; projCam.viewport()->applyOpenGL(oglContext, Viewport::DO_NOT_CLEAR); if (software) { 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); #endif projCam.applyOpenGL(); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableVertexAttribArray(ShaderProgram::VERTEX); glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); backgroundShader = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); if (backgroundShader->useProgram(oglContext)) { MatrixState projMatrixState(projCam); backgroundShader->clearUniformApplyTracking(); backgroundShader->applyFixedUniforms(oglContext, projMatrixState); } } Vec3f min(1.0f, 1.0f, 0.0f); Vec3f max(static_cast<float>(size.x() - 1), static_cast<float>(size.y() - 1), 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_drawBackground) { if (software) { #ifndef CVF_OPENGL_ES glColor4fv(m_backgroundColor.ptr()); glBegin(GL_TRIANGLE_FAN); glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); glVertex3fv(v4); glEnd(); #endif } else { // Draw background UniformFloat backgroundColor("u_color", Color4f(m_backgroundColor)); backgroundShader->applyUniform(oglContext, backgroundColor); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } } if (m_drawBorder) { if (software) { #ifndef CVF_OPENGL_ES glColor3fv(m_borderColor.ptr()); glBegin(GL_LINE_LOOP); glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); glVertex3fv(v4); glEnd(); #endif } else { UniformFloat borderColor("u_color", Color4f(m_borderColor)); backgroundShader->applyUniform(oglContext, borderColor); RenderStateLine line(static_cast<float>(3)); line.applyOpenGL(oglContext); // Draw border glDrawArrays(GL_LINE_LOOP, 0, 4); RenderStateLine resetLine; resetLine.applyOpenGL(oglContext); } } }
//-------------------------------------------------------------------------------------------------- /// 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); }