Files
fs2open.github.com/code/graphics/paths/NVGRenderer.cpp
T

381 lines
7.3 KiB
C++

#include "globalincs/pstypes.h"
#if SCP_COMPILER_IS_GNU
// Disable warnings inside the NanoVG implementation
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include "graphics/paths/NVGRenderer.h"
#include "graphics/opengl/gropengl.h"
#include "graphics/opengl/gropenglstate.h"
#include "graphics/opengl/gropengltnl.h"
#include "graphics/opengl/gropenglshader.h"
#include "nanovg/nanovg.h"
// NanoVG supports OpenGL 2 and 3, we currently use OpenGL 2
//#define NANOVG_GL2_IMPLEMENTATION
#define NANOVG_GL3_IMPLEMENTATION
#include "nanovg/nanovg_gl.h"
#if SCP_COMPILER_IS_GNU
#pragma GCC diagnostic pop
#endif
namespace
{
void resetGLState()
{
// After we are done with nanovg we need to tell our state tracker that things have changed
GL_state.Blend(GL_TRUE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_state.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_state.SetAlphaBlendMode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
GL_state.CullFace(GL_FALSE);
GL_state.CullFaceValue(GL_BACK);
GL_state.FrontFaceValue(GL_CCW);
GL_state.DepthTest(GL_FALSE);
GL_state.ScissorTest(GL_FALSE);
GL_state.ColorMask(GL_TRUE);
GL_state.SetStencilType(STENCIL_TYPE_WRITE);
GL_state.StencilTest(GL_TRUE);
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(0);
if ( GL_version >= 30 ) {
glBindVertexArray(GL_vao);
}
GL_state.Array.BindArrayBuffer(0);
GL_state.Array.BindUniformBuffer(0);
opengl_shader_set_current(nullptr);
// Now reset the values to what we need
GL_state.SetStencilType(STENCIL_TYPE_NONE);
GL_state.StencilTest(GL_FALSE);
}
NVGcolor fsColorToNVG(color* c)
{
return nvgRGBA(c->red, c->green, c->blue, c->is_alphacolor ? c->alpha : 255);
}
}
namespace graphics
{
namespace paths
{
NVGRenderer::NVGRenderer() : m_inFrame(false)
{
m_context = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
}
NVGRenderer::~NVGRenderer()
{
if (m_context)
{
nvgDeleteGL3(m_context);
m_context = nullptr;
}
}
void NVGRenderer::beginFrame()
{
Assertion(!m_inFrame, "beginFrame() was called withoug ending previous frame! Check your path renderer calls or get a coder!");
nvgBeginFrame(m_context, gr_screen.max_w, gr_screen.max_h, 1.0f);
m_inFrame = true;
}
void NVGRenderer::cancelFrame()
{
nvgCancelFrame(m_context);
m_inFrame = false;
}
void NVGRenderer::endFrame()
{
GR_DEBUG_SCOPE("NanoVG flush");
if ( GL_version >= 30 ) {
glBindVertexArray(0);
}
gr_opengl_set_2d_matrix();
nvgEndFrame(m_context);
gr_opengl_end_2d_matrix();
resetGLState();
m_inFrame = false;
}
void NVGRenderer::scissor(float x, float y, float w, float h)
{
nvgScissor(m_context, x, y, w, h);
}
void NVGRenderer::resetScissor()
{
nvgResetScissor(m_context);
}
void NVGRenderer::resetTransform()
{
nvgResetTransform(m_context);
}
void NVGRenderer::translate(float x, float y)
{
nvgTranslate(m_context, x, y);
}
void NVGRenderer::rotate(float rad)
{
nvgRotate(m_context, rad);
}
void NVGRenderer::skewX(float rad)
{
nvgSkewX(m_context, rad);
}
void NVGRenderer::skewY(float rad)
{
nvgSkewY(m_context, rad);
}
void NVGRenderer::scale(float x, float y)
{
nvgScale(m_context, x, y);
}
DrawPaint NVGRenderer::createLinearGradient(float sx, float sy, float ex,
float ey, color* icol, color* ocol)
{
DrawPaint p;
p.nvg = nvgLinearGradient(m_context, sx, sy, ex, ey, fsColorToNVG(icol), fsColorToNVG(ocol));
return p;
}
void NVGRenderer::setAlpha(float alpha)
{
nvgGlobalAlpha(m_context, alpha);
}
void NVGRenderer::setFillColor(color* color)
{
nvgFillColor(m_context, fsColorToNVG(color));
}
void NVGRenderer::setFillPaint(const DrawPaint& paint)
{
nvgFillPaint(m_context, paint.nvg);
}
void NVGRenderer::setStrokeColor(color* color)
{
nvgStrokeColor(m_context, fsColorToNVG(color));
}
void NVGRenderer::setStrokePaint(const DrawPaint& paint)
{
nvgStrokePaint(m_context, paint.nvg);
}
void NVGRenderer::setStrokeWidth(float width)
{
nvgStrokeWidth(m_context, width);
}
void NVGRenderer::beginPath()
{
nvgBeginPath(m_context);
}
void NVGRenderer::moveTo(float x, float y)
{
nvgMoveTo(m_context, x, y);
}
void NVGRenderer::setSolidity(Solidity solid)
{
int nvgSolid;
switch (solid)
{
case SOLIDITY_HOLE:
nvgSolid = NVG_HOLE;
break;
case SOLIDITY_SOLID:
nvgSolid = NVG_SOLID;
break;
default:
nvgSolid = NVG_SOLID;
break;
}
nvgPathWinding(m_context, nvgSolid);
}
void NVGRenderer::lineTo(float x, float y)
{
nvgLineTo(m_context, x, y);
}
void NVGRenderer::rectangle(float x, float y, float w, float h)
{
nvgRect(m_context, x, y, w, h);
}
void NVGRenderer::roundedRectangle(float x, float y, float w, float h, float radius)
{
nvgRoundedRect(m_context, x, y, w, h, radius);
}
void NVGRenderer::circle(float x, float y, float r)
{
nvgCircle(m_context, x, y, r);
}
void NVGRenderer::ellipse(float x, float y, float rx, float ry)
{
nvgEllipse(m_context, x, y, rx, ry);
}
void NVGRenderer::arc(float cx, float cy, float r, float a0, float a1, Direction dir)
{
int nvgDir;
switch (dir)
{
case DIR_CCW:
nvgDir = NVG_CCW;
break;
case DIR_CW:
nvgDir = NVG_CW;
break;
default:
nvgDir = NVG_CW;
break;
}
nvgArc(m_context, cx, cy, r, a0, a1, nvgDir);
}
void NVGRenderer::closePath()
{
nvgClosePath(m_context);
}
int NVGRenderer::createFontMem(const char* name, unsigned char* data, int ndata, int freeData)
{
return nvgCreateFontMem(m_context, name, data, ndata, freeData);
}
void NVGRenderer::fontSize(float size)
{
nvgFontSize(m_context, size);
}
void NVGRenderer::textLetterSpacing(float spacing)
{
nvgTextLetterSpacing(m_context, spacing);
}
void NVGRenderer::fontFaceId(int font)
{
nvgFontFaceId(m_context, font);
}
float NVGRenderer::text(float x, float y, const char* string, const char* end)
{
auto res = nvgText(m_context, x, y, string, end);
resetGLState();
return res;
}
float NVGRenderer::textBounds(float x, float y, const char* string, const char* end, float* bounds)
{
return nvgTextBounds(m_context, x, y, string, end, bounds);
}
void NVGRenderer::textMetrics(float* ascender, float* descender, float* lineh)
{
nvgTextMetrics(m_context, ascender, descender, lineh);
}
void NVGRenderer::textAlign(TextAlign align)
{
int nvgAlign = 0;
if (align & ALIGN_LEFT)
{
nvgAlign |= NVG_ALIGN_LEFT;
}
if (align & ALIGN_CENTER)
{
nvgAlign |= NVG_ALIGN_CENTER;
}
if (align & ALIGN_RIGHT)
{
nvgAlign |= NVG_ALIGN_RIGHT;
}
if (align & ALIGN_TOP)
{
nvgAlign |= NVG_ALIGN_TOP;
}
if (align & ALIGN_MIDDLE)
{
nvgAlign |= NVG_ALIGN_MIDDLE;
}
if (align & ALIGN_BOTTOM)
{
nvgAlign |= NVG_ALIGN_BOTTOM;
}
if (align & ALIGN_BASELINE)
{
nvgAlign |= NVG_ALIGN_BASELINE;
}
nvgTextAlign(m_context, nvgAlign);
}
void NVGRenderer::fill()
{
nvgFill(m_context);
}
void NVGRenderer::stroke()
{
nvgStroke(m_context);
}
void NVGRenderer::saveState()
{
nvgSave(m_context);
}
void NVGRenderer::resetState()
{
nvgReset(m_context);
}
void NVGRenderer::restoreState()
{
nvgRestore(m_context);
}
}
}