Add OpenGL 4.6 backend for NanoVG

This commit introduces a new header file `nanovg_gl46.h` that implements
the NanoVG rendering context using OpenGL 4.6. The new backend utilizes
Direct State Access (DSA) functions, immutable texture storage, and
explicit layout qualifiers. It includes definitions for creating and
deleting the rendering context, as well as functions for handling images
with OpenGL 4.6.
This commit is contained in:
Diego Lopes
2026-03-21 14:00:59 -04:00
parent 47be135221
commit 6200b74e77
12 changed files with 1849 additions and 2 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@ cmake/
*.flac
*.aac
*.opus
external/nanovg

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "external/nanovg"]
path = external/nanovg
url = https://github.com/memononen/nanovg.git

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc-14",
"cStandard": "c11",
"cppStandard": "c++20",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

View File

@@ -57,9 +57,9 @@ if(stb_ADDED)
add_library(stb INTERFACE)
target_include_directories(stb INTERFACE ${stb_SOURCE_DIR})
endif()
# ── Local dependencies ───────────────────────────────────────────────────────
add_subdirectory(external/glad)
add_subdirectory(external/nanovg)
find_package(OpenGL REQUIRED)
find_package(X11 REQUIRED)
@@ -90,6 +90,7 @@ target_link_libraries(${PROJECT_NAME}
Lua::Library
sol2
stb
nanovg
glad
PkgConfig::GST
)

1
external/nanovg vendored Submodule

Submodule external/nanovg added at ce3bf745eb

BIN
samples/font.otf Normal file

Binary file not shown.

View File

@@ -1,5 +1,11 @@
effect = nil
video = nil
ctx = nil
timeDisplayText = ""
dateDisplayText = ""
timer = 0.0
function _create()
video = Texture.FromGStreamer("filesrc location=" .. Resolve("video.mkv"))
@@ -21,10 +27,28 @@ function _create()
}
]]
effect = Effect.new(fxSrc)
ctx = GraphicsContext.new()
local fontPath = Resolve("font.otf")
ctx:CreateFont("font", fontPath)
UpdateTimeAndDate()
end
function UpdateTimeAndDate()
local now = os.date("*t")
timeDisplayText = string.format("%02d:%02d", now.hour, now.min)
dateDisplayText = os.date("%A, %B %d, %Y")
end
function _update(dt)
timer = timer + dt
if timer >= 0.5 then
timer = 0.0
UpdateTimeAndDate()
end
end
function _render()
@@ -32,4 +56,23 @@ function _render()
effect:Use()
effect:SetTexture("uTexture", video, 0)
effect:Render()
ctx:BeginFrame(DesktopSize.x, DesktopSize.y, DesktopSize.x / DesktopSize.y)
local xPos = 80.0
local yPos = 120.0
local timeFontSize = 80
local dateFontSize = 28
ctx:FontSize(timeFontSize)
ctx:FontFace("font")
ctx:FillColor(RGBAf(1, 1, 1, 0.75))
ctx:TextAlign(Align.RIGHT | Align.BOTTOM)
ctx:Text(Displays[1].x + Displays[1].z - xPos, Displays[1].y + Displays[1].w - yPos, timeDisplayText)
ctx:FontSize(dateFontSize)
ctx:FillColor(RGBAf(1, 1, 1, 0.45))
ctx:Text(Displays[1].x + Displays[1].z - xPos, Displays[1].y + Displays[1].w - (yPos + timeFontSize + 8), dateDisplayText)
ctx:EndFrame()
end

View File

@@ -8,6 +8,7 @@
#include "framebuffer.h"
#include "effect.h"
#include "opengl.h"
#include "nanovg_cpp.h"
#include "globals.h"
static void RegisterTMath(sol::state& lua) {
@@ -403,13 +404,234 @@ static void RegisterOpenGL(sol::state& lua) {
gl["ONE_MINUS_DST_ALPHA"] = GL_ONE_MINUS_DST_ALPHA;
}
#pragma region NanoVG bindings
static void RegisterNanoVG(sol::state& lua) {
// ── NVGcolor ─────────────────────────────────────────────────────────
lua.new_usertype<NVGcolor>("Color",
sol::constructors<>(),
"r", &NVGcolor::r,
"g", &NVGcolor::g,
"b", &NVGcolor::b,
"a", &NVGcolor::a,
sol::meta_function::to_string, [](const NVGcolor& c) {
return "Color(" + std::to_string(c.r) + ", " + std::to_string(c.g) + ", " + std::to_string(c.b) + ", " + std::to_string(c.a) + ")";
}
);
// ── NVGpaint ────────────────────────────────────────────────────────
lua.new_usertype<NVGpaint>("Paint",
sol::constructors<>(),
"innerColor", &NVGpaint::innerColor,
"outerColor", &NVGpaint::outerColor,
"image", &NVGpaint::image,
"radius", &NVGpaint::radius,
"feather", &NVGpaint::feather
);
// ── NVG Enums ───────────────────────────────────────────────────────
lua.new_enum<NVGwinding>("Winding", {
{ "CCW", NVG_CCW },
{ "CW", NVG_CW }
});
lua.new_enum<NVGsolidity>("Solidity", {
{ "SOLID", NVG_SOLID },
{ "HOLE", NVG_HOLE }
});
lua.new_enum<NVGlineCap>("LineCap", {
{ "BUTT", NVG_BUTT },
{ "ROUND", NVG_ROUND },
{ "SQUARE", NVG_SQUARE },
{ "BEVEL", NVG_BEVEL },
{ "MITER", NVG_MITER }
});
lua.new_enum<NVGalign>("Align", {
{ "LEFT", NVG_ALIGN_LEFT },
{ "CENTER", NVG_ALIGN_CENTER },
{ "RIGHT", NVG_ALIGN_RIGHT },
{ "TOP", NVG_ALIGN_TOP },
{ "MIDDLE", NVG_ALIGN_MIDDLE },
{ "BOTTOM", NVG_ALIGN_BOTTOM },
{ "BASELINE", NVG_ALIGN_BASELINE }
});
lua.new_enum<NVGcompositeOperation>("CompositeOperation", {
{ "SOURCE_OVER", NVG_SOURCE_OVER },
{ "SOURCE_IN", NVG_SOURCE_IN },
{ "SOURCE_OUT", NVG_SOURCE_OUT },
{ "ATOP", NVG_ATOP },
{ "DESTINATION_OVER", NVG_DESTINATION_OVER },
{ "DESTINATION_IN", NVG_DESTINATION_IN },
{ "DESTINATION_OUT", NVG_DESTINATION_OUT },
{ "DESTINATION_ATOP", NVG_DESTINATION_ATOP },
{ "LIGHTER", NVG_LIGHTER },
{ "COPY", NVG_COPY },
{ "XOR", NVG_XOR }
});
lua.create_named_table("ImageFlags",
"GENERATE_MIPMAPS", NVG_IMAGE_GENERATE_MIPMAPS,
"REPEATX", NVG_IMAGE_REPEATX,
"REPEATY", NVG_IMAGE_REPEATY,
"FLIPY", NVG_IMAGE_FLIPY,
"PREMULTIPLIED", NVG_IMAGE_PREMULTIPLIED,
"NEAREST", NVG_IMAGE_NEAREST
);
// ── GraphicsContext ─────────────────────────────────────────────────
lua.new_usertype<GraphicsContext>("GraphicsContext",
sol::constructors<GraphicsContext()>(),
// Frame management
"BeginFrame", &GraphicsContext::BeginFrame,
"CancelFrame", &GraphicsContext::CancelFrame,
"EndFrame", &GraphicsContext::EndFrame,
// Composite operations
"GlobalCompositeOperation", &GraphicsContext::GlobalCompositeOperation,
"GlobalCompositeBlendFunc", &GraphicsContext::GlobalCompositeBlendFunc,
"GlobalCompositeBlendFuncSeparate", &GraphicsContext::GlobalCompositeBlendFuncSeparate,
// State handling
"Save", &GraphicsContext::Save,
"Restore", &GraphicsContext::Restore,
"Reset", &GraphicsContext::Reset,
// Render styles
"ShapeAntiAlias", &GraphicsContext::ShapeAntiAlias,
"StrokeColor", &GraphicsContext::StrokeColor,
"StrokePaint", &GraphicsContext::StrokePaint,
"FillColor", &GraphicsContext::FillColor,
"FillPaint", &GraphicsContext::FillPaint,
"MiterLimit", &GraphicsContext::MiterLimit,
"StrokeWidth", &GraphicsContext::StrokeWidth,
"LineCap", &GraphicsContext::LineCap,
"LineJoin", &GraphicsContext::LineJoin,
"GlobalAlpha", &GraphicsContext::GlobalAlpha,
// Transforms
"ResetTransform", &GraphicsContext::ResetTransform,
"Transform", &GraphicsContext::Transform,
"Translate", &GraphicsContext::Translate,
"Rotate", &GraphicsContext::Rotate,
"SkewX", &GraphicsContext::SkewX,
"SkewY", &GraphicsContext::SkewY,
"Scale", &GraphicsContext::Scale,
"DegToRad", &GraphicsContext::DegToRad,
"RadToDeg", &GraphicsContext::RadToDeg,
// Images
"CreateImage", &GraphicsContext::CreateImage,
"CreateImageRGBA", &GraphicsContext::CreateImageRGBA,
"ImageSize", [](GraphicsContext& g, int image) -> std::pair<int, int> {
return g.ImageSize(image);
},
"DeleteImage", &GraphicsContext::DeleteImage,
// Paints (gradients & patterns)
"LinearGradient", &GraphicsContext::LinearGradient,
"BoxGradient", &GraphicsContext::BoxGradient,
"RadialGradient", &GraphicsContext::RadialGradient,
"ImagePattern", &GraphicsContext::ImagePattern,
// Scissoring
"Scissor", &GraphicsContext::Scissor,
"IntersectScissor", &GraphicsContext::IntersectScissor,
"ResetScissor", &GraphicsContext::ResetScissor,
// Paths
"BeginPath", &GraphicsContext::BeginPath,
"MoveTo", &GraphicsContext::MoveTo,
"LineTo", &GraphicsContext::LineTo,
"BezierTo", &GraphicsContext::BezierTo,
"QuadTo", &GraphicsContext::QuadTo,
"ArcTo", &GraphicsContext::ArcTo,
"ClosePath", &GraphicsContext::ClosePath,
"PathWinding", &GraphicsContext::PathWinding,
"Arc", &GraphicsContext::Arc,
"Rect", &GraphicsContext::Rect,
"RoundedRect", &GraphicsContext::RoundedRect,
"RoundedRectVarying", &GraphicsContext::RoundedRectVarying,
"Ellipse", &GraphicsContext::Ellipse,
"Circle", &GraphicsContext::Circle,
"Fill", &GraphicsContext::Fill,
"Stroke", &GraphicsContext::Stroke,
// Fonts
"CreateFont", &GraphicsContext::CreateFont,
"CreateFontAtIndex", &GraphicsContext::CreateFontAtIndex,
"FindFont", &GraphicsContext::FindFont,
"AddFallbackFontId", &GraphicsContext::AddFallbackFontId,
"AddFallbackFont", &GraphicsContext::AddFallbackFont,
"ResetFallbackFontsId", &GraphicsContext::ResetFallbackFontsId,
"ResetFallbackFonts", &GraphicsContext::ResetFallbackFonts,
// Text styling
"FontSize", &GraphicsContext::FontSize,
"FontBlur", &GraphicsContext::FontBlur,
"TextLetterSpacing", &GraphicsContext::TextLetterSpacing,
"TextLineHeight", &GraphicsContext::TextLineHeight,
"TextAlign", &GraphicsContext::TextAlign,
"FontFaceId", &GraphicsContext::FontFaceId,
"FontFace", &GraphicsContext::FontFace,
// Text rendering & measurement
"Text", [](GraphicsContext& g, float x, float y, const std::string& str) -> float {
return g.Text(x, y, str.c_str());
},
"TextBox", [](GraphicsContext& g, float x, float y, float breakRowWidth, const std::string& str) {
g.TextBox(x, y, breakRowWidth, str.c_str());
},
"TextBounds", [](GraphicsContext& g, float x, float y, const std::string& str) -> std::tuple<float, float, float, float, float> {
float bounds[4];
float advance = g.TextBounds(x, y, str.c_str(), nullptr, bounds);
return { advance, bounds[0], bounds[1], bounds[2], bounds[3] };
},
"TextBoxBounds", [](GraphicsContext& g, float x, float y, float breakRowWidth, const std::string& str) -> std::tuple<float, float, float, float> {
float bounds[4];
g.TextBoxBounds(x, y, breakRowWidth, str.c_str(), nullptr, bounds);
return { bounds[0], bounds[1], bounds[2], bounds[3] };
},
"TextMetrics", [](GraphicsContext& g) -> std::tuple<float, float, float> {
return g.TextMetrics();
}
);
// Loose functions
lua.set_function("RGB", &GraphicsContext::RGB);
lua.set_function("RGBf", &GraphicsContext::RGBf);
lua.set_function("RGBA", &GraphicsContext::RGBA);
lua.set_function("RGBAf", &GraphicsContext::RGBAf);
lua.set_function("LerpRGBA", &GraphicsContext::LerpRGBA);
lua.set_function("TransRGBA", &GraphicsContext::TransRGBA);
lua.set_function("TransRGBAf", &GraphicsContext::TransRGBAf);
lua.set_function("HSL", &GraphicsContext::HSL);
lua.set_function("HSLA", &GraphicsContext::HSLA);
// Matrices/utils
lua.set_function("DegToRad", &GraphicsContext::DegToRad);
lua.set_function("RadToDeg", &GraphicsContext::RadToDeg);
lua.set_function("Rotate", &GraphicsContext::Rotate);
lua.set_function("Translate", &GraphicsContext::Translate);
lua.set_function("Scale", &GraphicsContext::Scale);
}
#pragma endregion
void RegisterLuaBindings(sol::state& lua) {
lua.open_libraries(
sol::lib::base,
sol::lib::math,
sol::lib::string,
sol::lib::table,
sol::lib::package
sol::lib::package,
sol::lib::os,
sol::lib::io,
sol::lib::coroutine
);
RegisterTMath(lua);
@@ -417,6 +639,7 @@ void RegisterLuaBindings(sol::state& lua) {
RegisterFrameBuffer(lua);
RegisterEffect(lua);
RegisterOpenGL(lua);
RegisterNanoVG(lua);
// Globals
lua["DesktopSize"] = g_DesktopSize;

171
src/nanovg_cpp.cpp Normal file
View File

@@ -0,0 +1,171 @@
#include "nanovg_cpp.h"
GraphicsContext::GraphicsContext()
{
ctx = nvgCreateGL46(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
}
GraphicsContext::~GraphicsContext()
{
if (ctx) {
nvgDeleteGL46(ctx);
ctx = nullptr;
}
}
// Frame management
void GraphicsContext::BeginFrame(float width, float height, float devicePixelRatio)
{
nvgBeginFrame(ctx, width, height, devicePixelRatio);
}
void GraphicsContext::CancelFrame() { nvgCancelFrame(ctx); }
void GraphicsContext::EndFrame()
{
nvgEndFrame(ctx);
glBindVertexArray(0);
glDisable(GL_STENCIL_TEST);
glDisable(GL_CULL_FACE);
glUseProgram(0);
}
// Composite operations
void GraphicsContext::GlobalCompositeOperation(int op) { nvgGlobalCompositeOperation(ctx, op); }
void GraphicsContext::GlobalCompositeBlendFunc(int sfactor, int dfactor) { nvgGlobalCompositeBlendFunc(ctx, sfactor, dfactor); }
void GraphicsContext::GlobalCompositeBlendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) { nvgGlobalCompositeBlendFuncSeparate(ctx, srcRGB, dstRGB, srcAlpha, dstAlpha); }
// Color utilities
NVGcolor GraphicsContext::RGB(unsigned char r, unsigned char g, unsigned char b) { return nvgRGB(r, g, b); }
NVGcolor GraphicsContext::RGBf(float r, float g, float b) { return nvgRGBf(r, g, b); }
NVGcolor GraphicsContext::RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { return nvgRGBA(r, g, b, a); }
NVGcolor GraphicsContext::RGBAf(float r, float g, float b, float a) { return nvgRGBAf(r, g, b, a); }
NVGcolor GraphicsContext::LerpRGBA(NVGcolor c0, NVGcolor c1, float u) { return nvgLerpRGBA(c0, c1, u); }
NVGcolor GraphicsContext::TransRGBA(NVGcolor c0, unsigned char a) { return nvgTransRGBA(c0, a); }
NVGcolor GraphicsContext::TransRGBAf(NVGcolor c0, float a) { return nvgTransRGBAf(c0, a); }
NVGcolor GraphicsContext::HSL(float h, float s, float l) { return nvgHSL(h, s, l); }
NVGcolor GraphicsContext::HSLA(float h, float s, float l, unsigned char a) { return nvgHSLA(h, s, l, a); }
// State handling
void GraphicsContext::Save() { nvgSave(ctx); }
void GraphicsContext::Restore() { nvgRestore(ctx); }
void GraphicsContext::Reset() { nvgReset(ctx); }
// Render styles
void GraphicsContext::ShapeAntiAlias(int enabled) { nvgShapeAntiAlias(ctx, enabled); }
void GraphicsContext::StrokeColor(NVGcolor color) { nvgStrokeColor(ctx, color); }
void GraphicsContext::StrokePaint(NVGpaint paint) { nvgStrokePaint(ctx, paint); }
void GraphicsContext::FillColor(NVGcolor color) { nvgFillColor(ctx, color); }
void GraphicsContext::FillPaint(NVGpaint paint) { nvgFillPaint(ctx, paint); }
void GraphicsContext::MiterLimit(float limit) { nvgMiterLimit(ctx, limit); }
void GraphicsContext::StrokeWidth(float size) { nvgStrokeWidth(ctx, size); }
void GraphicsContext::LineCap(int cap) { nvgLineCap(ctx, cap); }
void GraphicsContext::LineJoin(int join) { nvgLineJoin(ctx, join); }
void GraphicsContext::GlobalAlpha(float alpha) { nvgGlobalAlpha(ctx, alpha); }
// Transforms
void GraphicsContext::ResetTransform() { nvgResetTransform(ctx); }
void GraphicsContext::Transform(float a, float b, float c, float d, float e, float f) { nvgTransform(ctx, a, b, c, d, e, f); }
void GraphicsContext::Translate(float x, float y) { nvgTranslate(ctx, x, y); }
void GraphicsContext::Rotate(float angle) { nvgRotate(ctx, angle); }
void GraphicsContext::SkewX(float angle) { nvgSkewX(ctx, angle); }
void GraphicsContext::SkewY(float angle) { nvgSkewY(ctx, angle); }
void GraphicsContext::Scale(float x, float y) { nvgScale(ctx, x, y); }
void GraphicsContext::CurrentTransform(float* xform) { nvgCurrentTransform(ctx, xform); }
// Transform matrix utilities
void GraphicsContext::TransformIdentity(float* dst) { nvgTransformIdentity(dst); }
void GraphicsContext::TransformTranslate(float* dst, float tx, float ty) { nvgTransformTranslate(dst, tx, ty); }
void GraphicsContext::TransformScale(float* dst, float sx, float sy) { nvgTransformScale(dst, sx, sy); }
void GraphicsContext::TransformRotate(float* dst, float a) { nvgTransformRotate(dst, a); }
void GraphicsContext::TransformSkewX(float* dst, float a) { nvgTransformSkewX(dst, a); }
void GraphicsContext::TransformSkewY(float* dst, float a) { nvgTransformSkewY(dst, a); }
void GraphicsContext::TransformMultiply(float* dst, const float* src) { nvgTransformMultiply(dst, src); }
void GraphicsContext::TransformPremultiply(float* dst, const float* src) { nvgTransformPremultiply(dst, src); }
int GraphicsContext::TransformInverse(float* dst, const float* src) { return nvgTransformInverse(dst, src); }
void GraphicsContext::TransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy) { nvgTransformPoint(dstx, dsty, xform, srcx, srcy); }
float GraphicsContext::DegToRad(float deg) { return nvgDegToRad(deg); }
float GraphicsContext::RadToDeg(float rad) { return nvgRadToDeg(rad); }
// Images
int GraphicsContext::CreateImage(const char* filename, int imageFlags) { return nvgCreateImage(ctx, filename, imageFlags); }
int GraphicsContext::CreateImageMem(int imageFlags, unsigned char* data, int ndata) { return nvgCreateImageMem(ctx, imageFlags, data, ndata); }
int GraphicsContext::CreateImageRGBA(int w, int h, int imageFlags, const unsigned char* data) { return nvgCreateImageRGBA(ctx, w, h, imageFlags, data); }
void GraphicsContext::UpdateImage(int image, const unsigned char* data) { nvgUpdateImage(ctx, image, data); }
void GraphicsContext::ImageSize(int image, int* w, int* h) { nvgImageSize(ctx, image, w, h); }
std::pair<int, int> GraphicsContext::ImageSize(int image) { int w, h; nvgImageSize(ctx, image, &w, &h); return {w, h}; }
void GraphicsContext::DeleteImage(int image) { nvgDeleteImage(ctx, image); }
// Paints (gradients & patterns)
NVGpaint GraphicsContext::LinearGradient(float sx, float sy, float ex, float ey, NVGcolor icol, NVGcolor ocol) { return nvgLinearGradient(ctx, sx, sy, ex, ey, icol, ocol); }
NVGpaint GraphicsContext::BoxGradient(float x, float y, float w, float h, float r, float f, NVGcolor icol, NVGcolor ocol) { return nvgBoxGradient(ctx, x, y, w, h, r, f, icol, ocol); }
NVGpaint GraphicsContext::RadialGradient(float cx, float cy, float inr, float outr, NVGcolor icol, NVGcolor ocol) { return nvgRadialGradient(ctx, cx, cy, inr, outr, icol, ocol); }
NVGpaint GraphicsContext::ImagePattern(float ox, float oy, float ex, float ey, float angle, int image, float alpha) { return nvgImagePattern(ctx, ox, oy, ex, ey, angle, image, alpha); }
// Scissoring
void GraphicsContext::Scissor(float x, float y, float w, float h) { nvgScissor(ctx, x, y, w, h); }
void GraphicsContext::IntersectScissor(float x, float y, float w, float h) { nvgIntersectScissor(ctx, x, y, w, h); }
void GraphicsContext::ResetScissor() { nvgResetScissor(ctx); }
// Paths
void GraphicsContext::BeginPath() { nvgBeginPath(ctx); }
void GraphicsContext::MoveTo(float x, float y) { nvgMoveTo(ctx, x, y); }
void GraphicsContext::LineTo(float x, float y) { nvgLineTo(ctx, x, y); }
void GraphicsContext::BezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y) { nvgBezierTo(ctx, c1x, c1y, c2x, c2y, x, y); }
void GraphicsContext::QuadTo(float cx, float cy, float x, float y) { nvgQuadTo(ctx, cx, cy, x, y); }
void GraphicsContext::ArcTo(float x1, float y1, float x2, float y2, float radius) { nvgArcTo(ctx, x1, y1, x2, y2, radius); }
void GraphicsContext::ClosePath() { nvgClosePath(ctx); }
void GraphicsContext::PathWinding(int dir) { nvgPathWinding(ctx, dir); }
void GraphicsContext::Arc(float cx, float cy, float r, float a0, float a1, int dir) { nvgArc(ctx, cx, cy, r, a0, a1, dir); }
void GraphicsContext::Rect(float x, float y, float w, float h) { nvgRect(ctx, x, y, w, h); }
void GraphicsContext::RoundedRect(float x, float y, float w, float h, float r) { nvgRoundedRect(ctx, x, y, w, h, r); }
void GraphicsContext::RoundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft) { nvgRoundedRectVarying(ctx, x, y, w, h, radTopLeft, radTopRight, radBottomRight, radBottomLeft); }
void GraphicsContext::Ellipse(float cx, float cy, float rx, float ry) { nvgEllipse(ctx, cx, cy, rx, ry); }
void GraphicsContext::Circle(float cx, float cy, float r) { nvgCircle(ctx, cx, cy, r); }
void GraphicsContext::Fill() { nvgFill(ctx); }
void GraphicsContext::Stroke() { nvgStroke(ctx); }
// Fonts
int GraphicsContext::CreateFont(const char* name, const char* filename) { return nvgCreateFont(ctx, name, filename); }
int GraphicsContext::CreateFontAtIndex(const char* name, const char* filename, int fontIndex) { return nvgCreateFontAtIndex(ctx, name, filename, fontIndex); }
int GraphicsContext::CreateFontMem(const char* name, unsigned char* data, int ndata, int freeData) { return nvgCreateFontMem(ctx, name, data, ndata, freeData); }
int GraphicsContext::CreateFontMemAtIndex(const char* name, unsigned char* data, int ndata, int freeData, int fontIndex) { return nvgCreateFontMemAtIndex(ctx, name, data, ndata, freeData, fontIndex); }
int GraphicsContext::FindFont(const char* name) { return nvgFindFont(ctx, name); }
int GraphicsContext::AddFallbackFontId(int baseFont, int fallbackFont) { return nvgAddFallbackFontId(ctx, baseFont, fallbackFont); }
int GraphicsContext::AddFallbackFont(const char* baseFont, const char* fallbackFont) { return nvgAddFallbackFont(ctx, baseFont, fallbackFont); }
void GraphicsContext::ResetFallbackFontsId(int baseFont) { nvgResetFallbackFontsId(ctx, baseFont); }
void GraphicsContext::ResetFallbackFonts(const char* baseFont) { nvgResetFallbackFonts(ctx, baseFont); }
// Text styling
void GraphicsContext::FontSize(float size) { nvgFontSize(ctx, size); }
void GraphicsContext::FontBlur(float blur) { nvgFontBlur(ctx, blur); }
void GraphicsContext::TextLetterSpacing(float spacing) { nvgTextLetterSpacing(ctx, spacing); }
void GraphicsContext::TextLineHeight(float lineHeight) { nvgTextLineHeight(ctx, lineHeight); }
void GraphicsContext::TextAlign(int align) { nvgTextAlign(ctx, align); }
void GraphicsContext::FontFaceId(int font) { nvgFontFaceId(ctx, font); }
void GraphicsContext::FontFace(const char* font) { nvgFontFace(ctx, font); }
// Text rendering & measurement
float GraphicsContext::Text(float x, float y, const char* string, const char* end) { return nvgText(ctx, x, y, string, end); }
void GraphicsContext::TextBox(float x, float y, float breakRowWidth, const char* string, const char* end) { nvgTextBox(ctx, x, y, breakRowWidth, string, end); }
float GraphicsContext::TextBounds(float x, float y, const char* string, const char* end, float* bounds) { return nvgTextBounds(ctx, x, y, string, end, bounds); }
void GraphicsContext::TextBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds) { nvgTextBoxBounds(ctx, x, y, breakRowWidth, string, end, bounds); }
int GraphicsContext::TextGlyphPositions(float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions) { return nvgTextGlyphPositions(ctx, x, y, string, end, positions, maxPositions); }
void GraphicsContext::TextMetrics(float* ascender, float* descender, float* lineh) { nvgTextMetrics(ctx, ascender, descender, lineh); }
std::tuple<float, float, float> GraphicsContext::TextMetrics() { float a, d, l; nvgTextMetrics(ctx, &a, &d, &l); return {a, d, l}; }
int GraphicsContext::TextBreakLines(const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows) { return nvgTextBreakLines(ctx, string, end, breakRowWidth, rows, maxRows); }

149
src/nanovg_cpp.h Normal file
View File

@@ -0,0 +1,149 @@
#pragma once
#include "nanovg.h"
#include "nanovg_gl46.h"
#include <tuple>
#include <utility>
class GraphicsContext {
public:
GraphicsContext();
~GraphicsContext();
NVGcontext* GetNVG() const { return ctx; }
// Frame management
void BeginFrame(float width, float height, float devicePixelRatio);
void CancelFrame();
void EndFrame();
// Composite operations
void GlobalCompositeOperation(int op);
void GlobalCompositeBlendFunc(int sfactor, int dfactor);
void GlobalCompositeBlendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
// Color utilities (static)
static NVGcolor RGB(unsigned char r, unsigned char g, unsigned char b);
static NVGcolor RGBf(float r, float g, float b);
static NVGcolor RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
static NVGcolor RGBAf(float r, float g, float b, float a);
static NVGcolor LerpRGBA(NVGcolor c0, NVGcolor c1, float u);
static NVGcolor TransRGBA(NVGcolor c0, unsigned char a);
static NVGcolor TransRGBAf(NVGcolor c0, float a);
static NVGcolor HSL(float h, float s, float l);
static NVGcolor HSLA(float h, float s, float l, unsigned char a);
// State handling
void Save();
void Restore();
void Reset();
// Render styles
void ShapeAntiAlias(int enabled);
void StrokeColor(NVGcolor color);
void StrokePaint(NVGpaint paint);
void FillColor(NVGcolor color);
void FillPaint(NVGpaint paint);
void MiterLimit(float limit);
void StrokeWidth(float size);
void LineCap(int cap);
void LineJoin(int join);
void GlobalAlpha(float alpha);
// Transforms
void ResetTransform();
void Transform(float a, float b, float c, float d, float e, float f);
void Translate(float x, float y);
void Rotate(float angle);
void SkewX(float angle);
void SkewY(float angle);
void Scale(float x, float y);
void CurrentTransform(float* xform);
// Transform matrix utilities (static)
static void TransformIdentity(float* dst);
static void TransformTranslate(float* dst, float tx, float ty);
static void TransformScale(float* dst, float sx, float sy);
static void TransformRotate(float* dst, float a);
static void TransformSkewX(float* dst, float a);
static void TransformSkewY(float* dst, float a);
static void TransformMultiply(float* dst, const float* src);
static void TransformPremultiply(float* dst, const float* src);
static int TransformInverse(float* dst, const float* src);
static void TransformPoint(float* dstx, float* dsty, const float* xform, float srcx, float srcy);
static float DegToRad(float deg);
static float RadToDeg(float rad);
// Images
int CreateImage(const char* filename, int imageFlags);
int CreateImageMem(int imageFlags, unsigned char* data, int ndata);
int CreateImageRGBA(int w, int h, int imageFlags, const unsigned char* data);
void UpdateImage(int image, const unsigned char* data);
void ImageSize(int image, int* w, int* h);
std::pair<int, int> ImageSize(int image);
void DeleteImage(int image);
// Paints (gradients & patterns)
NVGpaint LinearGradient(float sx, float sy, float ex, float ey, NVGcolor icol, NVGcolor ocol);
NVGpaint BoxGradient(float x, float y, float w, float h, float r, float f, NVGcolor icol, NVGcolor ocol);
NVGpaint RadialGradient(float cx, float cy, float inr, float outr, NVGcolor icol, NVGcolor ocol);
NVGpaint ImagePattern(float ox, float oy, float ex, float ey, float angle, int image, float alpha);
// Scissoring
void Scissor(float x, float y, float w, float h);
void IntersectScissor(float x, float y, float w, float h);
void ResetScissor();
// Paths
void BeginPath();
void MoveTo(float x, float y);
void LineTo(float x, float y);
void BezierTo(float c1x, float c1y, float c2x, float c2y, float x, float y);
void QuadTo(float cx, float cy, float x, float y);
void ArcTo(float x1, float y1, float x2, float y2, float radius);
void ClosePath();
void PathWinding(int dir);
void Arc(float cx, float cy, float r, float a0, float a1, int dir);
void Rect(float x, float y, float w, float h);
void RoundedRect(float x, float y, float w, float h, float r);
void RoundedRectVarying(float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft);
void Ellipse(float cx, float cy, float rx, float ry);
void Circle(float cx, float cy, float r);
void Fill();
void Stroke();
// Fonts
int CreateFont(const char* name, const char* filename);
int CreateFontAtIndex(const char* name, const char* filename, int fontIndex);
int CreateFontMem(const char* name, unsigned char* data, int ndata, int freeData);
int CreateFontMemAtIndex(const char* name, unsigned char* data, int ndata, int freeData, int fontIndex);
int FindFont(const char* name);
int AddFallbackFontId(int baseFont, int fallbackFont);
int AddFallbackFont(const char* baseFont, const char* fallbackFont);
void ResetFallbackFontsId(int baseFont);
void ResetFallbackFonts(const char* baseFont);
// Text styling
void FontSize(float size);
void FontBlur(float blur);
void TextLetterSpacing(float spacing);
void TextLineHeight(float lineHeight);
void TextAlign(int align);
void FontFaceId(int font);
void FontFace(const char* font);
// Text rendering & measurement
float Text(float x, float y, const char* string, const char* end = nullptr);
void TextBox(float x, float y, float breakRowWidth, const char* string, const char* end = nullptr);
float TextBounds(float x, float y, const char* string, const char* end, float* bounds);
void TextBoxBounds(float x, float y, float breakRowWidth, const char* string, const char* end, float* bounds);
int TextGlyphPositions(float x, float y, const char* string, const char* end, NVGglyphPosition* positions, int maxPositions);
void TextMetrics(float* ascender, float* descender, float* lineh);
std::tuple<float, float, float> TextMetrics();
int TextBreakLines(const char* string, const char* end, float breakRowWidth, NVGtextRow* rows, int maxRows);
private:
NVGcontext* ctx = nullptr;
};

1208
src/nanovg_gl46.cpp Normal file

File diff suppressed because it is too large Load Diff

31
src/nanovg_gl46.h Normal file
View File

@@ -0,0 +1,31 @@
//
// NanoVG OpenGL 4.6 Core Profile backend
//
// Based on nanovg_gl.h by Mikko Mononen (Copyright (c) 2009-2013)
// Adapted to use OpenGL 4.6 Direct State Access (DSA) functions,
// immutable texture storage, and explicit layout qualifiers.
//
#pragma once
#include "glad/gl.h"
struct NVGcontext;
// Create flags (same as nanovg_gl.h, guarded to avoid redefinition)
#ifndef NANOVG_GL_H
enum NVGcreateFlags {
NVG_ANTIALIAS = 1 << 0,
NVG_STENCIL_STROKES = 1 << 1,
NVG_DEBUG = 1 << 2,
};
enum NVGimageFlagsGL {
NVG_IMAGE_NODELETE = 1 << 16,
};
#endif
NVGcontext* nvgCreateGL46(int flags);
void nvgDeleteGL46(NVGcontext* ctx);
int nvglCreateImageFromHandleGL46(NVGcontext* ctx, GLuint textureId, int w, int h, int flags);
GLuint nvglImageHandleGL46(NVGcontext* ctx, int image);