blob: 30f0e083f421a317e06691b8bbf82248ccfa0d9f [file]
#include "opengl/opengl_renderer.hpp"
#include "opengl/opengl_render_path.hpp"
#include "opengl/opengl_render_paint.hpp"
#include "opengl_shaders.cpp"
#include <cassert>
using namespace rive;
GLuint createAndCompileShader(GLuint type, const char* source);
OpenGLRenderer::OpenGLRenderer() {}
OpenGLRenderer::~OpenGLRenderer()
{
glDeleteProgram(m_Program);
glDeleteShader(m_VertexShader);
glDeleteShader(m_FragmentShader);
glDeleteBuffers(1, &m_IndexBuffer);
glDeleteVertexArrays(1, &m_VertexArray);
}
bool OpenGLRenderer::initialize(void* data)
{
assert(m_VertexShader == 0 && m_FragmentShader == 0 && m_Program == 0);
m_VertexShader =
createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource);
if (m_VertexShader == 0)
{
return false;
}
m_FragmentShader =
createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
if (m_FragmentShader == 0)
{
return false;
}
m_Program = glCreateProgram();
glAttachShader(m_Program, m_VertexShader);
glAttachShader(m_Program, m_FragmentShader);
glLinkProgram(m_Program);
GLint isLinked = 0;
glGetProgramiv(m_Program, GL_LINK_STATUS, (int*)&isLinked);
if (isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(m_Program, maxLength, &maxLength, &infoLog[0]);
fprintf(stderr, "Failed to link program %s\n", &infoLog[0]);
return false;
}
// Create index buffer which we'll grow and populate as necessary.
glGenBuffers(1, &m_IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IndexBuffer);
// 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");
m_FillTypeUniformIndex = glGetUniformLocation(m_Program, "fillType");
m_StopCountUniformIndex = glGetUniformLocation(m_Program, "count");
m_StopColorsUniformIndex = glGetUniformLocation(m_Program, "colors");
m_StopsUniformIndex = glGetUniformLocation(m_Program, "stops");
m_ColorUniformIndex = glGetUniformLocation(m_Program, "color");
m_GradientPositionUniformIndex =
glGetUniformLocation(m_Program, "position");
m_ShapeTransformUniformIndex =
glGetUniformLocation(m_Program, "localTransform");
float projection[16] = {0.0f};
orthographicProjection(projection, 0.0f, 800, 800, 0.0f, 0.0f, 1.0f);
modelViewProjection(projection);
return true;
}
void OpenGLRenderer::drawPath(RenderPath* path, RenderPaint* paint)
{
auto glPaint = static_cast<OpenGLRenderPaint*>(paint);
if (glPaint->style() == RenderPaintStyle::stroke || !glPaint->doesDraw())
{
return;
}
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);
glPaint->draw(this, transform(), glPath);
// glPath->cover(this, transform());
}
void OpenGLRenderer::clipPath(RenderPath* path) {}
void OpenGLRenderer::startFrame()
{
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() {}
RenderPaint* OpenGLRenderer::makeRenderPaint()
{
return new OpenGLRenderPaint();
}
RenderPath* OpenGLRenderer::makeRenderPath() { return new OpenGLRenderPath(); }
void OpenGLRenderer::updateIndexBuffer(std::size_t contourLength)
{
if (contourLength < 2)
{
return;
}
auto edgeCount = (m_Indices.size() - 6) / 3;
auto targetEdgeCount = contourLength - 2;
if (edgeCount < targetEdgeCount)
{
while (edgeCount < targetEdgeCount)
{
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,
m_Indices.size() * sizeof(unsigned short),
&m_Indices[0],
GL_STATIC_DRAW);
}
}
GLuint createAndCompileShader(GLuint type, const char* source)
{
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
fprintf(stderr, "Failed to compile shader %s\n", &infoLog[0]);
glDeleteShader(shader);
return 0;
}
return shader;
}