blob: de9e2de00024ee4193e8e6b61d3e166ce1b792a4 [file] [log] [blame]
#include "opengl/opengl_render_paint.hpp"
#include "opengl/opengl_renderer.hpp"
#include "opengl/opengl_render_path.hpp"
#include "rive/shapes/paint/color.hpp"
#include "rive/contour_stroke.hpp"
using namespace rive;
void fillColorBuffer(float* buffer, unsigned int value)
{
buffer[0] = colorRed(value) / 255.0f;
buffer[1] = colorGreen(value) / 255.0f;
buffer[2] = colorBlue(value) / 255.0f;
buffer[3] = colorAlpha(value) / 255.0f;
}
void OpenGLRenderPaint::style(RenderPaintStyle style)
{
m_PaintStyle = style;
delete m_Stroke;
if (m_PaintStyle == RenderPaintStyle::stroke)
{
m_Stroke = new ContourStroke();
m_StrokeDirty = true;
if (m_StrokeBuffer != 0)
{
glDeleteBuffers(1, &m_StrokeBuffer);
}
glGenBuffers(1, &m_StrokeBuffer);
}
else
{
m_Stroke = nullptr;
m_StrokeDirty = false;
}
}
void OpenGLRenderPaint::color(unsigned int value)
{
fillColorBuffer(m_Color, value);
}
void OpenGLRenderPaint::thickness(float value) { m_StrokeThickness = value; }
void OpenGLRenderPaint::join(StrokeJoin value) { m_StrokeJoin = value; }
void OpenGLRenderPaint::cap(StrokeCap value) { m_StrokeCap = value; }
void OpenGLRenderPaint::blendMode(BlendMode value) {}
void OpenGLRenderPaint::linearGradient(float sx, float sy, float ex, float ey)
{
if (m_Gradient == nullptr)
{
m_Gradient = new OpenGLGradient(1);
}
m_Gradient->position(sx, sy, ex, ey);
}
void OpenGLRenderPaint::radialGradient(float sx, float sy, float ex, float ey)
{
if (m_Gradient == nullptr)
{
m_Gradient = new OpenGLGradient(2);
}
m_Gradient->position(sx, sy, ex, ey);
}
void OpenGLRenderPaint::addStop(unsigned int color, float stop)
{
m_Gradient->addStop(color, stop);
}
void OpenGLRenderPaint::completeGradient() {}
void OpenGLRenderPaint::invalidateStroke()
{
if (m_Stroke != nullptr)
{
m_StrokeDirty = true;
}
}
OpenGLRenderPaint::~OpenGLRenderPaint()
{
if (m_StrokeBuffer != 0)
{
glDeleteBuffers(1, &m_StrokeBuffer);
}
delete m_Gradient;
delete m_Stroke;
}
bool OpenGLRenderPaint::doesDraw() const
{
return m_Color[3] > 0.0f &&
(m_Gradient == nullptr || m_Gradient->m_IsVisible);
}
void OpenGLRenderPaint::draw(OpenGLRenderer* renderer,
const Mat2D& transform,
OpenGLRenderPath* path)
{
uint32_t type = 0;
if (m_Gradient != nullptr)
{
type = m_Gradient->m_Type;
m_Gradient->bind(renderer);
}
glUniform1i(renderer->fillTypeUniformIndex(), type);
glUniform4fv(renderer->colorUniformIndex(), 1, m_Color);
if (m_Stroke != nullptr)
{
if (m_StrokeDirty)
{
static Mat2D identity;
m_Stroke->reset();
path->extrudeStroke(m_Stroke,
m_StrokeJoin,
m_StrokeCap,
m_StrokeThickness / 2.0f,
identity);
m_StrokeDirty = false;
}
const std::vector<Vec2D>& strip = m_Stroke->triangleStrip();
auto size = strip.size();
if (size == 0)
{
return;
}
glBindBuffer(GL_ARRAY_BUFFER, m_StrokeBuffer);
glBufferData(GL_ARRAY_BUFFER,
size * 2 * sizeof(float),
&strip[0][0],
GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * 4, (void*)0);
m_Stroke->resetRenderOffset();
path->renderStroke(m_Stroke, renderer, transform);
}
else
{
path->cover(renderer, transform);
}
}
OpenGLGradient::OpenGLGradient(int type) : m_Type(type) {}
void OpenGLGradient::position(float sx, float sy, float ex, float ey)
{
m_Colors.clear();
m_Stops.clear();
m_IsVisible = false;
m_Position[0] = sx;
m_Position[1] = sy;
m_Position[2] = ex;
m_Position[3] = ey;
}
void OpenGLGradient::bind(OpenGLRenderer* renderer)
{
auto numberOfStops = m_Stops.size();
glUniform1i(renderer->stopCountUniformIndex(), numberOfStops);
glUniform4fv(
renderer->stopColorsUniformIndex(), numberOfStops, &m_Colors[0]);
glUniform1fv(renderer->stopsUniformIndex(), numberOfStops, &m_Stops[0]);
glUniform4fv(renderer->gradientPositionUniformIndex(), 1, &m_Position[0]);
}
void OpenGLGradient::addStop(unsigned int color, float stop)
{
auto index = m_Colors.size();
m_Colors.resize(index + 4);
fillColorBuffer(&m_Colors[index], color);
if (m_Colors[index + 3] > 0.0f)
{
m_IsVisible = true;
}
m_Stops.push_back(stop);
}