mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
381 lines
7.3 KiB
C++
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);
|
|
}
|
|
}
|
|
}
|