Files
fs2open.github.com/code/graphics/paths/PathRenderer.cpp
asarium b9b556c7a5 Add a NanoVG renderer using the generic rendering API
One of the main points of contention when adding the NanoVG based
TrueType text rendering was that it required an external Opengl
renderer which may interfere with our rendering engine by changing
OpenGL state without telling the rest of the engine. Since the rendering
interface for NanoVG is abstract and can be easily replaced, I did just
that and replaced it with an implementation that uses only generic
graphics functions without relying on the specific graphics API.

This will improve the interoperability of NanoVG with our engine and
should make later changes to the rendering engine easier since there is
no external rendering code which may interfere with our own code.
2017-12-02 18:31:00 +01:00

264 lines
5.4 KiB
C++

#include "graphics/paths/PathRenderer.h"
#include "graphics/paths/NanoVGRenderer.h"
namespace {
NVGcolor fsColorToNVG(color* c) {
return nvgRGBA(c->red, c->green, c->blue, c->is_alphacolor ? c->alpha : 255);
}
}
namespace graphics {
namespace paths {
std::unique_ptr<PathRenderer> PathRenderer::s_instance;
bool PathRenderer::init() {
s_instance = std::unique_ptr<PathRenderer>(new PathRenderer());
return true;
}
void PathRenderer::shutdown() {
s_instance = nullptr;
}
PathRenderer::PathRenderer() : m_inFrame(false) {
m_context = createNanoVGContext();
}
PathRenderer::~PathRenderer() {
if (m_context) {
deleteNanoVGContext(m_context);
m_context = nullptr;
}
}
void PathRenderer::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 PathRenderer::cancelFrame() {
nvgCancelFrame(m_context);
m_inFrame = false;
}
void PathRenderer::endFrame() {
nvgEndFrame(m_context);
m_inFrame = false;
}
void PathRenderer::scissor(float x, float y, float w, float h) {
nvgScissor(m_context, x, y, w, h);
}
void PathRenderer::resetScissor() {
nvgResetScissor(m_context);
}
void PathRenderer::resetTransform() {
nvgResetTransform(m_context);
}
void PathRenderer::translate(float x, float y) {
nvgTranslate(m_context, x, y);
}
void PathRenderer::rotate(float rad) {
nvgRotate(m_context, rad);
}
void PathRenderer::skewX(float rad) {
nvgSkewX(m_context, rad);
}
void PathRenderer::skewY(float rad) {
nvgSkewY(m_context, rad);
}
void PathRenderer::scale(float x, float y) {
nvgScale(m_context, x, y);
}
DrawPaint PathRenderer::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 PathRenderer::setAlpha(float alpha) {
nvgGlobalAlpha(m_context, alpha);
}
void PathRenderer::setFillColor(color* color) {
nvgFillColor(m_context, fsColorToNVG(color));
}
void PathRenderer::setFillPaint(const DrawPaint& paint) {
nvgFillPaint(m_context, paint.nvg);
}
void PathRenderer::setStrokeColor(::color* color) {
nvgStrokeColor(m_context, fsColorToNVG(color));
}
void PathRenderer::setStrokePaint(const DrawPaint& paint) {
nvgStrokePaint(m_context, paint.nvg);
}
void PathRenderer::setStrokeWidth(float width) {
nvgStrokeWidth(m_context, width);
}
void PathRenderer::beginPath() {
nvgBeginPath(m_context);
}
void PathRenderer::moveTo(float x, float y) {
nvgMoveTo(m_context, x, y);
}
void PathRenderer::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 PathRenderer::lineTo(float x, float y) {
nvgLineTo(m_context, x, y);
}
void PathRenderer::rectangle(float x, float y, float w, float h) {
nvgRect(m_context, x, y, w, h);
}
void PathRenderer::roundedRectangle(float x, float y, float w, float h, float radius) {
nvgRoundedRect(m_context, x, y, w, h, radius);
}
void PathRenderer::circle(float x, float y, float r) {
nvgCircle(m_context, x, y, r);
}
void PathRenderer::ellipse(float x, float y, float rx, float ry) {
nvgEllipse(m_context, x, y, rx, ry);
}
void PathRenderer::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 PathRenderer::closePath() {
nvgClosePath(m_context);
}
int PathRenderer::createFontMem(const char* name, unsigned char* data, int ndata, int freeData) {
return nvgCreateFontMem(m_context, name, data, ndata, freeData);
}
void PathRenderer::fontSize(float size) {
nvgFontSize(m_context, size);
}
void PathRenderer::textLetterSpacing(float spacing) {
nvgTextLetterSpacing(m_context, spacing);
}
void PathRenderer::fontFaceId(int font) {
nvgFontFaceId(m_context, font);
}
float PathRenderer::text(float x, float y, const char* string, const char* end) {
return nvgText(m_context, x, y, string, end);
}
float PathRenderer::textBounds(float x, float y, const char* string, const char* end, float* bounds) {
return nvgTextBounds(m_context, x, y, string, end, bounds);
}
void PathRenderer::textMetrics(float* ascender, float* descender, float* lineh) {
nvgTextMetrics(m_context, ascender, descender, lineh);
}
void PathRenderer::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 PathRenderer::fill() {
nvgFill(m_context);
}
void PathRenderer::stroke() {
nvgStroke(m_context);
}
void PathRenderer::saveState() {
nvgSave(m_context);
}
void PathRenderer::resetState() {
nvgReset(m_context);
}
void PathRenderer::restoreState() {
nvgRestore(m_context);
}
}
}