Improving GL renderer.
diff --git a/renderer/library/build/premake5.lua b/renderer/library/build/premake5.lua index a8d16e4..a28d333 100644 --- a/renderer/library/build/premake5.lua +++ b/renderer/library/build/premake5.lua
@@ -11,7 +11,7 @@ if os.host() == "macosx" then links {"Cocoa.framework", "rive"} - defines {"PLATFORM_MACOS", "RIVE_HAS_METAL", "RIVE_HAS_OPENGL"} + defines {"RIVE_HAS_METAL", "RIVE_HAS_OPENGL"} defines {"GL_SILENCE_DEPRECATION"} includedirs {"../../dependencies/DiligentEngine_build/build/include"} files {"../src/**.mm"}
diff --git a/renderer/library/include/opengl/opengl.h b/renderer/library/include/opengl/opengl.h index 629bc12..1f1cd48 100644 --- a/renderer/library/include/opengl/opengl.h +++ b/renderer/library/include/opengl/opengl.h
@@ -9,8 +9,6 @@ #include <OpenGLES/ES2/glext.h> #else #include <OpenGL/gl3.h> -#include <OpenGL/glu.h> -#include <OpenGL/glext.h> #endif #elif defined(__ANDROID__) || defined(ANDROID) #include <GLES2/gl2.h>
diff --git a/renderer/library/include/opengl/opengl_render_path.hpp b/renderer/library/include/opengl/opengl_render_path.hpp index c704fce..050a214 100644 --- a/renderer/library/include/opengl/opengl_render_path.hpp +++ b/renderer/library/include/opengl/opengl_render_path.hpp
@@ -20,6 +20,7 @@ FillRule fillRule() const { return m_FillRule; } void stencil(OpenGLRenderer* renderer, const Mat2D& transform); + void cover(OpenGLRenderer* renderer, const Mat2D& transform); }; } // namespace rive #endif \ No newline at end of file
diff --git a/renderer/library/include/opengl/opengl_renderer.hpp b/renderer/library/include/opengl/opengl_renderer.hpp index 2304d3d..4f389bd 100644 --- a/renderer/library/include/opengl/opengl_renderer.hpp +++ b/renderer/library/include/opengl/opengl_renderer.hpp
@@ -17,6 +17,10 @@ GLuint m_IndexBuffer = 0; GLint m_ProjectionUniformIndex = -1; GLint m_TransformUniformIndex = -1; + GLuint m_VertexArray = 0; + + /// Indices for the max sized contour, prepended with 2 triangles for + /// bounding boxes. std::vector<unsigned short> m_Indices; public:
diff --git a/renderer/library/src/opengl/opengl_render_path.cpp b/renderer/library/src/opengl/opengl_render_path.cpp index 1286f6b..611cb40 100644 --- a/renderer/library/src/opengl/opengl_render_path.cpp +++ b/renderer/library/src/opengl/opengl_render_path.cpp
@@ -23,14 +23,16 @@ return; } - glUseProgram(renderer->program()); + // glUseProgram(renderer->program()); std::size_t vertexCount; if (isDirty()) { computeContour(); vertexCount = m_ContourVertices.size(); - renderer->updateIndexBuffer(vertexCount); + // We only want the indices to go from the off contour point (bounds' + // last point). First 4 points are bounds. + renderer->updateIndexBuffer(vertexCount - 3); glBindBuffer(GL_ARRAY_BUFFER, m_ContourBuffer); glBufferData(GL_ARRAY_BUFFER, @@ -44,12 +46,15 @@ vertexCount = m_ContourVertices.size(); } - if (vertexCount < 2) + // 4 vertices of bounds and one for the repeated start (repeated on close so + // we don't need to modulate indices and share them across all paths with + // different contours). + if (vertexCount < 5) { return; } - auto triangleCount = vertexCount - 2; + auto triangleCount = vertexCount - 5; // printf("VCOUNT: %i E: %i\n", vertexCount, triangleCount); // printf("X: %f %f\n", transform[0], transform[1]); // printf("Y: %f %f\n", transform[2], transform[3]); @@ -77,21 +82,80 @@ glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * 4, (void*)0); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // glDisable(GL_CULL_FACE); + // glDisable(GL_DEPTH_TEST); + // glEnable(GL_BLEND); + // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer()); - glDrawElements( - GL_TRIANGLES, triangleCount * 3, GL_UNSIGNED_SHORT, (void*)(0)); - GLenum err; - while ((err = glGetError()) != GL_NO_ERROR) - { - // Process/log the error. - fprintf(stderr, "ERRR:: %i\n", err); - } + // Index buffer offset is always after first 6 (2 triangles for bounds). + + // Draw the triangulated contour (triangle fans from the bottom left of the + // AABB) into the stencil buffer. + glDrawElements(GL_TRIANGLES, + triangleCount * 3, + GL_UNSIGNED_SHORT, + (void*)(6 * sizeof(unsigned short))); + + // GLenum err; + // while ((err = glGetError()) != GL_NO_ERROR) + // { + // // Process/log the error. + // fprintf(stderr, "ERRR:: %i\n", err); + // } // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // static unsigned short indices[3] = {0, 2, 2}; // glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, &indices[0]); +} + +void OpenGLRenderPath::cover(OpenGLRenderer* renderer, const Mat2D& transform) +{ + if (isContainer()) + { + for (auto& subPath : m_SubPaths) + { + Mat2D subPathTransform; + Mat2D::multiply(subPathTransform, transform, subPath.transform()); + reinterpret_cast<OpenGLRenderPath*>(subPath.path()) + ->stencil(renderer, subPathTransform); + } + return; + } + + glBindBuffer(GL_ARRAY_BUFFER, m_ContourBuffer); + auto vertexCount = m_ContourVertices.size(); + + if (vertexCount < 5) + { + return; + } + + auto triangleCount = vertexCount - 5; + + float m4[16] = {transform[0], + transform[1], + 0.0, + 0.0, + transform[2], + transform[3], + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + transform[4], + transform[5], + 0.0, + 1.0}; + + glUniformMatrix4fv(renderer->transformUniformIndex(), 1, GL_FALSE, m4); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * 4, (void*)0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, renderer->indexBuffer()); + + // Draw bounds. + glDrawElements(GL_TRIANGLES, 2 * 3, GL_UNSIGNED_SHORT, (void*)(0)); } \ No newline at end of file
diff --git a/renderer/library/src/opengl/opengl_renderer.cpp b/renderer/library/src/opengl/opengl_renderer.cpp index 9313548..fa0f741 100644 --- a/renderer/library/src/opengl/opengl_renderer.cpp +++ b/renderer/library/src/opengl/opengl_renderer.cpp
@@ -15,18 +15,17 @@ glDeleteShader(m_VertexShader); glDeleteShader(m_FragmentShader); glDeleteBuffers(1, &m_IndexBuffer); + glDeleteVertexArrays(1, &m_VertexArray); } bool OpenGLRenderer::initialize(void* data) { - fprintf(stderr, "init opengl\n"); assert(m_VertexShader == 0 && m_FragmentShader == 0 && m_Program == 0); m_VertexShader = createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource); if (m_VertexShader == 0) { - fprintf(stderr, "init opengl no 1"); return false; } @@ -34,7 +33,6 @@ createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); if (m_FragmentShader == 0) { - fprintf(stderr, "init opengl no 2"); return false; } @@ -57,18 +55,29 @@ // Create index buffer which we'll grow and populate as necessary. glGenBuffers(1, &m_IndexBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer); - // TODO: CLEANUP - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - printf("VAO: %i\n", vao); + // Two triangles for bounds. + m_Indices.emplace_back(0); + m_Indices.emplace_back(1); + m_Indices.emplace_back(2); + m_Indices.emplace_back(2); + m_Indices.emplace_back(3); + m_Indices.emplace_back(0); + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + m_Indices.size() * sizeof(unsigned short), + &m_Indices[0], + GL_STATIC_DRAW); + + glGenVertexArrays(1, &m_VertexArray); + glBindVertexArray(m_VertexArray); + glUseProgram(m_Program); m_ProjectionUniformIndex = glGetUniformLocation(m_Program, "projection"); m_TransformUniformIndex = glGetUniformLocation(m_Program, "transform"); - GLint position = glGetAttribLocation(m_Program, "position"); - fprintf(stderr, "POSITION: %i\n", position); + float projection[16] = {0.0f}; orthographicProjection(projection, 0.0f, 800, 800, 0.0f, 0.0f, 1.0f); modelViewProjection(projection); @@ -85,19 +94,34 @@ } auto glPath = static_cast<OpenGLRenderPath*>(path); + + // Set up stencil buffer. + glStencilMask(0xFF); + glStencilFunc(GL_ALWAYS, 0x0, 0xFF); + glColorMask(false, false, false, false); + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + glPath->stencil(this, transform()); + + glColorMask(true, true, true, true); + glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + glPath->cover(this, transform()); } void OpenGLRenderer::clipPath(RenderPath* path) {} void OpenGLRenderer::startFrame() { - // glClearColor(0.0f, 1.0f, 1.0f, 1.0f); - // glClear(GL_COLOR_BUFFER_BIT); glUseProgram(m_Program); glEnableVertexAttribArray(0); glUniformMatrix4fv( m_ProjectionUniformIndex, 1, GL_FALSE, m_ModelViewProjection); + glEnable(GL_STENCIL_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void OpenGLRenderer::endFrame() {} @@ -114,22 +138,21 @@ { return; } - auto edgeCount = m_Indices.size() / 3; + auto edgeCount = (m_Indices.size() - 6) / 3; auto targetEdgeCount = contourLength - 2; if (edgeCount < targetEdgeCount) { - while (edgeCount < targetEdgeCount) { - m_Indices.push_back(0); - m_Indices.push_back(edgeCount + 1); - m_Indices.push_back(edgeCount + 2); + m_Indices.push_back(3); + m_Indices.push_back(edgeCount + 4); + m_Indices.push_back(edgeCount + 5); edgeCount++; } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, - edgeCount * 3 * sizeof(unsigned short), + m_Indices.size() * sizeof(unsigned short), &m_Indices[0], GL_STATIC_DRAW); }
diff --git a/renderer/library/src/opengl/opengl_shaders.cpp b/renderer/library/src/opengl/opengl_shaders.cpp index 5e593f4..8ada16f 100644 --- a/renderer/library/src/opengl/opengl_shaders.cpp +++ b/renderer/library/src/opengl/opengl_shaders.cpp
@@ -36,7 +36,7 @@ void main() { - fragColor = vec4(0.3, 0.3, 0.3, 0.3); + fragColor = vec4(0.0, 0.0, 0.0, 0.35); // if (fillType == 0) // {
diff --git a/renderer/viewer/build/premake5.lua b/renderer/viewer/build/premake5.lua index d047561..79d9b46 100644 --- a/renderer/viewer/build/premake5.lua +++ b/renderer/viewer/build/premake5.lua
@@ -23,6 +23,7 @@ links {"Cocoa.framework", "IOKit.framework", "CoreVideo.framework", "Metal.framework", "QuartzCore.framework", "OpenGL.framework", "glfw3"} defines {"RIVE_HAS_OPENGL", "RIVE_HAS_METAL"} + defines {"GL_SILENCE_DEPRECATION"} includedirs {"%{DEPENDENCIES_DIR}/include/gl3w"} files {"../src/**.mm"} end
diff --git a/renderer/viewer/src/gl.cpp b/renderer/viewer/src/gl.cpp index e17e845..e2339d0 100644 --- a/renderer/viewer/src/gl.cpp +++ b/renderer/viewer/src/gl.cpp
@@ -2,6 +2,16 @@ #include "opengl/opengl_renderer.hpp" namespace rive { - LowLevelRenderer* makeRendererOpenGL() { return new OpenGLRenderer(); } + class ViewerGLRenderer : public OpenGLRenderer + { + public: + void startFrame() override + { + glClearColor(0.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + OpenGLRenderer::startFrame(); + } + }; + LowLevelRenderer* makeRendererOpenGL() { return new ViewerGLRenderer(); } } // namespace rive #endif \ No newline at end of file
diff --git a/renderer/viewer/src/viewer.cpp b/renderer/viewer/src/viewer.cpp index dcca39c..79b3112 100644 --- a/renderer/viewer/src/viewer.cpp +++ b/renderer/viewer/src/viewer.cpp
@@ -63,6 +63,7 @@ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_SAMPLES, 16); } else { @@ -77,8 +78,6 @@ return -1; } - void* windowHandle = nullptr; - #ifdef __APPLE__ glfwMakeContextCurrent(window); viewerNativeWindowHandle = static_cast<void*>(glfwGetCocoaWindow(window));
diff --git a/src/contour_render_path_recursive.cpp b/src/contour_render_path_recursive.cpp index 560e512..51ab2ad 100644 --- a/src/contour_render_path_recursive.cpp +++ b/src/contour_render_path_recursive.cpp
@@ -119,7 +119,13 @@ m_IsDirty = false; assert(m_ContourVertices.empty()); RecursiveCubicSegmenter segmenter(&m_ContourVertices, m_ContourThreshold); + + // First four vertices are the bounds. m_ContourVertices.emplace_back(Vec2D()); + m_ContourVertices.emplace_back(Vec2D()); + m_ContourVertices.emplace_back(Vec2D()); + m_ContourVertices.emplace_back(Vec2D()); + for (rive::PathCommand& command : m_Commands) { switch (command.type()) @@ -154,9 +160,21 @@ segmenter.close(); // TODO: consider if there's a case with no points. - Vec2D& first = m_ContourVertices[0]; AABB::copy(m_ContourBounds, segmenter.bounds()); + Vec2D& first = m_ContourVertices[0]; first[0] = m_ContourBounds.minX; first[1] = m_ContourBounds.minY; + + Vec2D& second = m_ContourVertices[1]; + second[0] = m_ContourBounds.maxX; + second[1] = m_ContourBounds.minY; + + Vec2D& third = m_ContourVertices[2]; + third[0] = m_ContourBounds.maxX; + third[1] = m_ContourBounds.maxY; + + Vec2D& fourth = m_ContourVertices[3]; + fourth[0] = m_ContourBounds.minX; + fourth[1] = m_ContourBounds.maxY; } #endif \ No newline at end of file