Use local context instead of global

This commit is contained in:
Joey Yakimowich-Payne 2020-04-25 22:07:47 -06:00
commit 77e390e9be
6 changed files with 302 additions and 274 deletions

View file

@ -18,34 +18,34 @@ proc currentSourceDir*(): string {.inline.} =
# Config # Config
proc drawLabel*(text: string, x, y, w, h: float) = proc drawLabel*(vg: Context, text: string, x, y, w, h: float) =
nanovg.setFontSize(50.0) vg.setFontSize(50.0)
nanovg.setFont("sans") vg.setFont("sans")
nanovg.setFillColor(1.0, 1.0, 1.0, 1.0) vg.setFillColor(1.0, 1.0, 1.0, 1.0)
nanovg.textAlign("left middle") vg.textAlign("left middle")
nanovg.text(text, x, y+h*0.5) vg.text(text, x, y+h*0.5)
proc drawWindow*(title: string, x, y, w, h: float) = proc drawWindow*(vg: Context, title: string, x, y, w, h: float) =
let cornerRadius = 3.0 let cornerRadius = 3.0
withState: withState(vg):
nanovg.beginPath() vg.beginPath()
nanovg.pathRoundedRect(x, y, w, h, cornerRadius) vg.pathRoundedRect(x, y, w, h, cornerRadius)
#nanovg.setFillColor(rgba(255,255,255,192)) #vg.setFillColor(rgba(255,255,255,192))
nanovg.setFillColor(rgba(28,30,34,192)) vg.setFillColor(rgba(28,30,34,192))
nanovg.pathFill() vg.pathFill()
nanovg.setFontSize(30.0) vg.setFontSize(30.0)
nanovg.setFont("sans") vg.setFont("sans")
nanovg.textAlign("center middle") vg.textAlign("center middle")
nanovg.setFontBlur(2) vg.setFontBlur(2)
nanovg.setFillColor(rgba(0,0,0,128)) vg.setFillColor(rgba(0,0,0,128))
nanovg.text(title, x+w/2, y+16+1) vg.text(title, x+w/2, y+16+1)
nanovg.setFontBlur(0) vg.setFontBlur(0)
nanovg.setFillColor(rgba(220,220,220,160)) vg.setFillColor(rgba(220,220,220,160))
nanovg.text(title, x+w/2,y+16) vg.text(title, x+w/2,y+16)
proc isBlack*(color: Color): bool = proc isBlack*(color: Color): bool =
result = true result = true
@ -93,8 +93,8 @@ proc cpToUtf8*(code: int): string =
return res return res
proc drawButton*(text: string, x, y, width, height: float) = proc drawButton*(vg: Context, text: string, x, y, width, height: float) =
let bg = linearGradient( let bg = vg.linearGradient(
x, y, x, y+height, x, y, x, y+height,
rgba(255, 255, 255, 16), rgba(255, 255, 255, 16),
rgba(100, 100, 100, 16) rgba(100, 100, 100, 16)
@ -109,28 +109,28 @@ proc drawButton*(text: string, x, y, width, height: float) =
let drawShadow = true let drawShadow = true
if drawShadow: if drawShadow:
nanovg.beginPath() vg.beginPath()
nanovg.pathRoundedRect(x+1+shadowOffset, y+1+shadowOffset, width-2, height-2, radius) vg.pathRoundedRect(x+1+shadowOffset, y+1+shadowOffset, width-2, height-2, radius)
nanovg.setFillColor(shadowColor) vg.setFillColor(shadowColor)
nanovg.pathFill() vg.pathFill()
nanovg.beginPath() vg.beginPath()
nanovg.pathRoundedRect(x+1, y+1, width-2, height-2, radius) vg.pathRoundedRect(x+1, y+1, width-2, height-2, radius)
nanovg.setFillColor(color) vg.setFillColor(color)
nanovg.pathFill() vg.pathFill()
nanovg.setFillPaint(bg) vg.setFillPaint(bg)
nanovg.pathFill() vg.pathFill()
nanovg.beginPath() vg.beginPath()
nanovg.pathMoveTo(x+radius, y+lightWidth+1) vg.pathMoveTo(x+radius, y+lightWidth+1)
nanovg.setStrokeWidth(lightWidth) vg.setStrokeWidth(lightWidth)
nanovg.setStrokeColor(highlightColor) vg.setStrokeColor(highlightColor)
nanovg.pathLineTo(x+width-(radius), y+lightWidth+1) vg.pathLineTo(x+width-(radius), y+lightWidth+1)
nanovg.pathStroke() vg.pathStroke()
proc drawButton*(preicon: string, text: string, x, y, w, h: float, color: Color) = proc drawButton*(vg: Context, preicon: string, text: string, x, y, w, h: float, color: Color) =
var var
bg: Paint bg: Paint
@ -140,50 +140,50 @@ proc drawButton*(preicon: string, text: string, x, y, w, h: float, color: Color)
tw = 0.0 tw = 0.0
iw = 0.0 iw = 0.0
bg = nanovg.linearGradient( bg = vg.linearGradient(
x,y,x,y+h, x,y,x,y+h,
rgba(255,255,255, if isBlack(color): 16 else:32), rgba(255,255,255, if isBlack(color): 16 else:32),
rgba(0,0,0, if isBlack(color): 16 else:32) rgba(0,0,0, if isBlack(color): 16 else:32)
) )
nanovg.beginPath() vg.beginPath()
nanovg.pathRoundedRect(x+1, y+1, w-2, h-2, cornerRadius-1) vg.pathRoundedRect(x+1, y+1, w-2, h-2, cornerRadius-1)
if not isBlack(color): if not isBlack(color):
nanovg.setFillColor(color) vg.setFillColor(color)
nanovg.pathFill() vg.pathFill()
nanovg.setFillPaint(bg) vg.setFillPaint(bg)
nanovg.pathFill() vg.pathFill()
nanovg.beginPath() vg.beginPath()
nanovg.pathRoundedRect(x+0.5, y+0.5, w-1, h-1, cornerRadius-0.5) vg.pathRoundedRect(x+0.5, y+0.5, w-1, h-1, cornerRadius-0.5)
nanovg.setStrokeColor(rgba(0,0,0,48)) vg.setStrokeColor(rgba(0,0,0,48))
nanovg.pathStroke() vg.pathStroke()
nanovg.setFontSize(20.0) vg.setFontSize(20.0)
nanovg.setFont("sans-bold") vg.setFont("sans-bold")
tb = nanovg.textBounds(text, 0.0, 0.0) tb = vg.textBounds(text, 0.0, 0.0)
tw = tb.horizontalAdvance tw = tb.horizontalAdvance
nanovg.setFontSize(h*0.5) vg.setFontSize(h*0.5)
nanovg.setFont("fa") vg.setFont("fa")
ib = nanovg.textBounds(preicon, 0, 0) ib = vg.textBounds(preicon, 0, 0)
iw = ib.horizontalAdvance iw = ib.horizontalAdvance
iw += h*0.15 iw += h*0.15
nanovg.setFontSize(h*0.5) vg.setFontSize(h*0.5)
nanovg.setFont("fa") vg.setFont("fa")
nanovg.setFillColor(rgba(255,255,255,96)) vg.setFillColor(rgba(255,255,255,96))
nanovg.textAlign("left middle") vg.textAlign("left middle")
nanovg.text(preicon, x+w*0.5-tw*0.5-iw*0.75, y+h*0.5) vg.text(preicon, x+w*0.5-tw*0.5-iw*0.75, y+h*0.5)
nanovg.setFontSize(20.0) vg.setFontSize(20.0)
nanovg.setFont("sans-bold") vg.setFont("sans-bold")
nanovg.textAlign("left middle") vg.textAlign("left middle")
nanovg.setFillColor(rgba(0,0,0,160)) vg.setFillColor(rgba(0,0,0,160))
nanovg.text(text, x+w*0.5-tw*0.5+iw*0.25, y+h*0.5-1) vg.text(text, x+w*0.5-tw*0.5+iw*0.25, y+h*0.5-1)
nanovg.setFillColor(rgba(255,255,255,160)) vg.setFillColor(rgba(255,255,255,160))
nanovg.text(text, x+w*0.5-tw*0.5+iw*0.25, y+h*0.5) vg.text(text, x+w*0.5-tw*0.5+iw*0.25, y+h*0.5)
proc glewInit*() {.header:"<GL/glew.h>".} proc glewInit*() {.header:"<GL/glew.h>".}

View file

@ -23,10 +23,10 @@ proc main =
setTime(0) setTime(0)
glewInit() glewInit()
nanovg.init() let vg = nanovg.newContext()
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans") vg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans")
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold") vg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold")
nanovg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa") vg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa")
var prevt = getTime() var prevt = getTime()
while not w.shouldClose(): while not w.shouldClose():
@ -43,16 +43,16 @@ proc main =
glClearColor(0.3, 0.3, 0.32, 1.0) glClearColor(0.3, 0.3, 0.32, 1.0)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
withFrame(w): vg.withFrame(w):
let x = glyphPositions("Some仮名thing is up", 0, 0) let x = vg.glyphPositions("Some仮名thing is up", 0, 0)
drawWindow("Title", 50, 50, 300, 400) vg.drawWindow("Title", 50, 50, 300, 400)
drawLabel("Hello!", 10, 10, 280, 20) vg.drawLabel("Hello!", 10, 10, 280, 20)
drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255)) vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255)) vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
drawButton("Testing", 100, 300, 160, 28) vg.drawButton("Testing", 100, 300, 160, 28)
fps.render(5, 5) vg.render(fps, 5, 5)
cpuGraph.render(210, 5) vg.render(cpuGraph, 210, 5)
w.swapBuffers() w.swapBuffers()
pollEvents() pollEvents()
@ -64,6 +64,7 @@ proc main =
waitEvents() waitEvents()
w.destroy() w.destroy()
vg.delete()
glfw.terminate() glfw.terminate()
main() main()

View file

@ -71,11 +71,11 @@ proc main() =
var prevt: float = sdl.getTicks().float/1000.0 var prevt: float = sdl.getTicks().float/1000.0
glewInit() glewInit()
nanovg.init() let vg = nanovg.newContext()
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans") vg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans")
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold") vg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold")
nanovg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa") vg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa")
nanovg.loadFont(currentSourceDir()/"resources/entypo.ttf", "icons") vg.loadFont(currentSourceDir()/"resources/entypo.ttf", "icons")
while not done: while not done:
let fbSize = window.frameBufferSize() let fbSize = window.frameBufferSize()
@ -86,16 +86,16 @@ proc main() =
glClearColor(0.3, 0.3, 0.32, 1.0) glClearColor(0.3, 0.3, 0.32, 1.0)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
withFrame(window): vg.withFrame(window):
let x = glyphPositions("Some仮名thing is up", 0, 0) let x = glyphPositions(vg, "Some仮名thing is up", 0, 0)
drawWindow("Title", 50, 50, 300, 400) vg.drawWindow("Title", 50, 50, 300, 400)
drawLabel("Hello!", 10, 10, 280, 20) vg.drawLabel("Hello!", 10, 10, 280, 20)
drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255)) vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255)) vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
drawButton("Testing", 100, 300, 160, 28) vg.drawButton("Testing", 100, 300, 160, 28)
fps.render(5, 5) vg.render(fps, 5, 5)
cpuGraph.render(210, 5) vg.render(cpuGraph, 210, 5)
let t: float = sdl.getTicks().float/1000.0 let t: float = sdl.getTicks().float/1000.0
let dt = t - prevt let dt = t - prevt
@ -112,6 +112,7 @@ proc main() =
sdl.glDeleteContext(context) sdl.glDeleteContext(context)
window.destroyWindow() window.destroyWindow()
vg.delete()
img.quit() img.quit()
sdl.quit() sdl.quit()

View file

@ -91,12 +91,12 @@ proc main() =
gpu.setRequiredFeatures(gpu.FEATURE_BASIC_SHADERS) gpu.setRequiredFeatures(gpu.FEATURE_BASIC_SHADERS)
nanovg.init() let vg = nanovg.newContext()
discard sdl.glSetSwapInterval(0) discard sdl.glSetSwapInterval(0)
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans") vg.loadFont(currentSourceDir()/"resources/umeboshi.ttf", "sans")
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold") vg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold")
nanovg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa") vg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa")
nanovg.loadFont(currentSourceDir()/"resources/entypo.ttf", "icons") vg.loadFont(currentSourceDir()/"resources/entypo.ttf", "icons")
var done = false var done = false
var prevt: float = sdl.getTicks().float/1000.0 var prevt: float = sdl.getTicks().float/1000.0
@ -122,18 +122,18 @@ proc main() =
gpu.flushBlitBuffer() gpu.flushBlitBuffer()
withFrame(window): withFrame(vg, window):
text("Some仮名thing is up", 100, 100, 100) vg.text("Some仮名thing is up", 100, 100, 100)
drawWindow("Title", 50, 50, 300, 400) vg.drawWindow("Title", 50, 50, 300, 400)
drawLabel("Hello!", 10, 10, 500, 20) vg.drawLabel("Hello!", 10, 10, 500, 20)
drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255)) vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255)) vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
drawButton("Testing", 100, 300, 160, 28) vg.drawButton("Testing", 100, 300, 160, 28)
gpu.resetRendererState() gpu.resetRendererState()
fps.render(5, 5) vg.render(fps, 5, 5)
cpuGraph.render(210, 5) vg.render(cpuGraph, 210, 5)
gpu.flip(screen) gpu.flip(screen)
@ -149,6 +149,7 @@ proc main() =
done = events() done = events()
gpu.freeImage(image) gpu.freeImage(image)
vg.delete()
gpu.quit() gpu.quit()
main() main()

View file

@ -32,19 +32,19 @@ proc getGraphAverage(graph: PerfGraph): float =
return avg / GRAPH_HISTORY_COUNT.float return avg / GRAPH_HISTORY_COUNT.float
proc render*(graph: PerfGraph, x, y: float) = proc render*(vg: Context, graph: PerfGraph, x, y: float) =
let let
avg = getGraphAverage(graph) avg = getGraphAverage(graph)
width: float = 200 width: float = 200
height: float = 35 height: float = 35
nanovg.beginPath() vg.beginPath()
nanovg.pathRect(x, y, width, height) vg.pathRect(x, y, width, height)
nanovg.setFillColor(0, 0, 0, 128) vg.setFillColor(0, 0, 0, 128)
nanovg.pathFill() vg.pathFill()
nanovg.beginPath() vg.beginPath()
nanovg.pathMoveTo(x, y+height) vg.pathMoveTo(x, y+height)
case graph.style: case graph.style:
of RenderStyle.FPS: of RenderStyle.FPS:
@ -58,7 +58,7 @@ proc render*(graph: PerfGraph, x, y: float) =
vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width
vy = y + height - ((v / 80) * height) vy = y + height - ((v / 80) * height)
nanovg.pathLineTo(vx, vy) vg.pathLineTo(vx, vy)
of RenderStyle.PERCENT: of RenderStyle.PERCENT:
for i in 0 ..< GRAPH_HISTORY_COUNT: for i in 0 ..< GRAPH_HISTORY_COUNT:
@ -71,7 +71,7 @@ proc render*(graph: PerfGraph, x, y: float) =
vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width
vy = y + height - ((v / 100) * height) vy = y + height - ((v / 100) * height)
nanovg.pathLineTo(vx, vy) vg.pathLineTo(vx, vy)
of RenderStyle.MS: of RenderStyle.MS:
for i in 0 ..< GRAPH_HISTORY_COUNT: for i in 0 ..< GRAPH_HISTORY_COUNT:
@ -84,40 +84,40 @@ proc render*(graph: PerfGraph, x, y: float) =
vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width vx = x + (i/(GRAPH_HISTORY_COUNT-1)) * width
vy = y + height - ((v / 20) * height) vy = y + height - ((v / 20) * height)
nanovg.pathLineTo(vx, vy) vg.pathLineTo(vx, vy)
nanovg.pathLineTo(x+width, y+height) vg.pathLineTo(x+width, y+height)
nanovg.setFillColor(255, 192, 0, 128) vg.setFillColor(255, 192, 0, 128)
nanovg.pathFill() vg.pathFill()
nanovg.setFont("sans") vg.setFont("sans")
if graph.name.len() > 0: if graph.name.len() > 0:
nanovg.setFontSize(14) vg.setFontSize(14)
nanovg.textAlign("top left") vg.textAlign("top left")
nanovg.setFillColor(240, 240, 240, 192) vg.setFillColor(240, 240, 240, 192)
nanovg.text(graph.name, x+3, y+1) vg.text(graph.name, x+3, y+1)
nanovg.setFontSize(18) vg.setFontSize(18)
nanovg.textAlign("top right") vg.textAlign("top right")
nanovg.setFillColor(240, 240, 240, 255) vg.setFillColor(240, 240, 240, 255)
case graph.style: case graph.style:
of RenderStyle.FPS: of RenderStyle.FPS:
var str = fmt"{1.0/avg:.2f} FPS" var str = fmt"{1.0/avg:.2f} FPS"
nanovg.text(str, x+width-3, y+1) vg.text(str, x+width-3, y+1)
nanovg.setFontSize(15) vg.setFontSize(15)
nanovg.textAlign("bottom right") vg.textAlign("bottom right")
nanovg.setFillColor(240, 240, 240, 160) vg.setFillColor(240, 240, 240, 160)
str = fmt"{avg*1000:.2f} ms" str = fmt"{avg*1000:.2f} ms"
nanovg.text(str, x+width-3, y+height-1) vg.text(str, x+width-3, y+height-1)
of RenderStyle.PERCENT: of RenderStyle.PERCENT:
let str = fmt"{avg:.1f} %" let str = fmt"{avg:.1f} %"
nanovg.text(str, x+width-3, y+1) vg.text(str, x+width-3, y+1)
of RenderStyle.MS: of RenderStyle.MS:
let str = fmt"{avg*1000:.2f} ms" let str = fmt"{avg*1000:.2f} ms"
nanovg.text(str, x+width-3, y+1) vg.text(str, x+width-3, y+1)

View file

@ -24,7 +24,7 @@ type
FontLoadError* = object of CatchableError FontLoadError* = object of CatchableError
ImageLoadError* = object of CatchableError ImageLoadError* = object of CatchableError
ContextInitError* = object of CatchableError ContextInitError* = object of CatchableError
Context = ptr NVGContext Context* = ptr NVGContext
Alignment* {.size: sizeof(cint), pure.} = enum Alignment* {.size: sizeof(cint), pure.} = enum
NONE = 0 NONE = 0
@ -114,7 +114,7 @@ type
proc width*(pos: GlyphPosition): float = proc width*(pos: GlyphPosition): float =
return pos.maxX - pos.minX return pos.maxX - pos.minX
proc createExpr*(ty, name: string, descriptor: NimNode, args: varargs[NimNode]): NimNode = proc createExpr*(context: NimNode, ty, name: string, descriptor: NimNode, args: varargs[NimNode]): NimNode =
let tokens = ($descriptor).toUpper().split(" ").map( let tokens = ($descriptor).toUpper().split(" ").map(
proc(s: string): string = proc(s: string): string =
return ty & "." & s return ty & "." & s
@ -127,7 +127,7 @@ proc createExpr*(ty, name: string, descriptor: NimNode, args: varargs[NimNode]):
let allTokens = argTokens.concat(tokens) let allTokens = argTokens.concat(tokens)
let newExpr = name & "(" & allTokens.join(",") & ")" let newExpr = name & "(" & $context.toStrLit & ", " & allTokens.join(",") & ")"
result = parseStmt(newExpr) result = parseStmt(newExpr)
@ -140,7 +140,10 @@ template reduce[T](elements: openArray[T], op: untyped): untyped =
res res
proc createContext(antialias = true, stencilStrokes = true, debugChecks = false): Context = proc delete*(context: Context) =
context.deleteGL3()
proc newContext*(antialias = true, stencilStrokes = true, debugChecks = false): Context =
var flags: cint var flags: cint
if antialias: if antialias:
@ -155,83 +158,78 @@ proc createContext(antialias = true, stencilStrokes = true, debugChecks = false)
if result.isNil: if result.isNil:
raise newException(ContextInitError, "Could not initialize graphics context") raise newException(ContextInitError, "Could not initialize graphics context")
var context: Context proc loadFont*(context: Context, path, name: string): Font {.discardable.} =
proc init*() =
context = createContext()
proc loadFont*(path, name: string): Font {.discardable.} =
## Load the font from `path` and give it a `name` that can be used to reference it. ## Load the font from `path` and give it a `name` that can be used to reference it.
result = context.createFont(name, path) result = context.createFont(name, path)
if result == -1: if result == -1:
raise newException(FontLoadError, fmt"Could not load font {name}.") raise newException(FontLoadError, fmt"Could not load font {name}.")
proc loadFontMem*(data: openArray[uint8], name: string, freeDataAutomatically = true): Font {.discardable.} = proc loadFontMem*(context: Context, data: openArray[uint8], name: string, freeDataAutomatically = true): Font {.discardable.} =
## Load the font from `path` and give it a `name` that can be used to reference it. ## Load the font from `path` and give it a `name` that can be used to reference it.
result = context.createFontMem(name, cast[ptr cuchar](data[0].unsafeAddr), data.len.cint, freeDataAutomatically.cint) result = context.createFontMem(name, cast[ptr cuchar](data[0].unsafeAddr), data.len.cint, freeDataAutomatically.cint)
if result == -1: if result == -1:
raise newException(FontLoadError, fmt"Could not load font {name}.") raise newException(FontLoadError, fmt"Could not load font {name}.")
proc findFont*(name: string): Font = proc findFont*(context: Context, name: string): Font =
return context.findFont(name) return context.findFont(name)
proc setFallbackFont*(baseFont, fallbackFont: string): Font = proc setFallbackFont*(context: Context, baseFont, fallbackFont: string): Font =
return context.addFallbackFont(baseFont, fallbackFont) return context.addFallbackFont(baseFont, fallbackFont)
proc setFallbackFont*(baseFont, fallbackFont: Font): Font = proc setFallbackFont*(context: Context, baseFont, fallbackFont: Font): Font =
return context.addFallbackFontId(baseFont, fallbackFont) return context.addFallbackFontId(baseFont, fallbackFont)
proc setFont*(font: Font) = proc `font=`*(context: Context, font: Font) =
context.fontFaceId(font) context.fontFaceId(font)
proc setFont*(name: string) = proc setFont*(context: Context, name: string) =
context.fontFace(name) context.fontFace(name)
proc setFontSize*(size: float) = proc setFontSize*(context: Context, size: float) =
context.fontSize(size) context.fontSize(size)
proc setFontBlur*(blur: float) = proc setFontBlur*(context: Context, blur: float) =
context.fontBlur(blur) context.fontBlur(blur)
proc setTextLetterSpacing*(spacing: float) = proc setTextLetterSpacing*(context: Context, spacing: float) =
context.textLetterSpacing(spacing) context.textLetterSpacing(spacing)
proc setTextLineHeight*(lineHeight: float) = proc setTextLineHeight*(context: Context, lineHeight: float) =
context.textLineHeight(lineHeight) context.textLineHeight(lineHeight)
proc `or`(align1: Alignment, align2: Alignment): Alignment = proc `or`(align1: Alignment, align2: Alignment): Alignment =
return (align1.cint or align2.cint).Alignment return (align1.cint or align2.cint).Alignment
proc textAlign*(alignments: varargs[Alignment]) = proc textAlign*(context: Context, alignments: varargs[Alignment]) =
var alignment = reduce(alignments, `or`) var alignment = reduce(alignments, `or`)
context.textAlign(alignment.cint) context.textAlign(alignment.cint)
macro textAlign*(descriptor: string) = macro textAlign*(context: Context, descriptor: string) =
result = createExpr("Alignment", "textAlign", descriptor) result = createExpr(context, "Alignment", "textAlign", descriptor)
proc textBounds*(text: string, x, y: float): TextBounds = proc textBounds*(context: Context, text: string, x, y: float): TextBounds =
var res: array[4, cfloat] var res: array[4, cfloat]
let horizonalAdvance = context.textBounds(x, y, text, nil, res[0].addr) let horizonalAdvance = context.textBounds(x, y, text, nil, res[0].addr)
let bounds: Bounds = (res[0].float, res[1].float, res[2].float, res[3].float) let bounds: Bounds = (res[0].float, res[1].float, res[2].float, res[3].float)
return (horizonalAdvance.float, bounds) return (horizonalAdvance.float, bounds)
proc text*(text: string, x, y: float) = proc text*(context: Context, text: string, x, y: float) =
discard context.text(x, y, text, nil) discard context.text(x, y, text, nil)
proc textBoxBounds*(text: string, x, y, breakRowWidth: float): Bounds = proc textBoxBounds*(context: Context, text: string, x, y, breakRowWidth: float): Bounds =
var res: array[4, cfloat] var res: array[4, cfloat]
context.textBoxBounds(x, y, breakRowWidth, text, nil, res[0].addr) context.textBoxBounds(x, y, breakRowWidth, text, nil, res[0].addr)
return (res[0].float, res[1].float, res[2].float, res[3].float) return (res[0].float, res[1].float, res[2].float, res[3].float)
proc textBox*(text: string, x, y, breakRowWidth: float) = proc textBox*(context: Context, text: string, x, y, breakRowWidth: float) =
context.textBox(x, y, breakRowWidth, text, nil) context.textBox(x, y, breakRowWidth, text, nil)
proc textMetrics*(): TextMetrics = proc textMetrics*(context: Context): TextMetrics =
var var
ascender, descender, lineHeight: cfloat ascender, descender, lineHeight: cfloat
@ -239,7 +237,7 @@ proc textMetrics*(): TextMetrics =
return (ascender.float, descender.float, lineHeight.float) return (ascender.float, descender.float, lineHeight.float)
iterator glyphPositions(start: cstring, endPos: cstring, x, y: float): GlyphPosition = iterator glyphPositions(context: Context, start: cstring, endPos: cstring, x, y: float): GlyphPosition =
const maxPositions = 100 const maxPositions = 100
var var
positions: array[maxPositions, NVGglyphPosition] positions: array[maxPositions, NVGglyphPosition]
@ -247,7 +245,7 @@ iterator glyphPositions(start: cstring, endPos: cstring, x, y: float): GlyphPosi
bytesProcessed = 0 bytesProcessed = 0
lastX = x lastX = x
strIndex = 0 strIndex = 0
lineHeight = textMetrics().lineHeight lineHeight = context.textMetrics().lineHeight
let strLen = cast[ByteAddress](endPos) - cast[ByteAddress](start) let strLen = cast[ByteAddress](endPos) - cast[ByteAddress](start)
@ -285,17 +283,17 @@ iterator glyphPositions(start: cstring, endPos: cstring, x, y: float): GlyphPosi
lastX = positions[numGlyphs-1].x lastX = positions[numGlyphs-1].x
strIndex += maxPositions strIndex += maxPositions
proc glyphPositions*(text: string, x, y: float): seq[GlyphPosition] = proc glyphPositions*(context: Context, text: string, x, y: float): seq[GlyphPosition] =
result = newSeqOfCap[GlyphPosition](100) result = newSeqOfCap[GlyphPosition](100)
for gpos in glyphPositions(cast[cstring](text[0].unsafeAddr), nil, x, y): for gpos in context.glyphPositions(cast[cstring](text[0].unsafeAddr), nil, x, y):
result.add gpos result.add gpos
proc glyphPositions*(row: NVGtextRow, x, y: float): seq[GlyphPosition] = proc glyphPositions*(context: Context, row: NVGtextRow, x, y: float): seq[GlyphPosition] =
result = newSeqOfCap[GlyphPosition](100) result = newSeqOfCap[GlyphPosition](100)
for gpos in glyphPositions(row.start, row.`end`, x, y): for gpos in context.glyphPositions(row.start, row.`end`, x, y):
result.add gpos result.add gpos
iterator textRows(text: string, x, y, maxWidth: float): NVGtextRow = iterator textRows(context: Context, text: string, x, y, maxWidth: float): NVGtextRow =
const maxRows = 10 const maxRows = 10
var var
rows: array[maxRows, NVGtextRow] rows: array[maxRows, NVGtextRow]
@ -315,48 +313,43 @@ iterator textRows(text: string, x, y, maxWidth: float): NVGtextRow =
start = rows[numRows-1].next start = rows[numRows-1].next
proc glyphPositions*(text: string, x, y, maxWidth: float): seq[GlyphPosition] = proc glyphPositions*(context: Context, text: string, x, y, maxWidth: float): seq[GlyphPosition] =
var newY = y var newY = y
for row in textRows(text, x, y, maxWidth): for row in context.textRows(text, x, y, maxWidth):
let glyphPositions = row.glyphPositions(x, newY) let glyphPositions = context.glyphPositions(row, x, newY)
result.add(glyphPositions) result.add(glyphPositions)
newY += glyphPositions[0].height newY += glyphPositions[0].height
proc text*(text: string, x, y, maxWidth: float) = proc text*(context: Context, text: string, x, y, maxWidth: float) =
var newY = y var newY = y
for row in textRows(text, x, y, maxWidth): for row in context.textRows(text, x, y, maxWidth):
discard context.text(x, newY, row.start, row.`end`) discard context.text(x, newY, row.start, row.`end`)
newY += textMetrics().lineHeight newY += context.textMetrics().lineHeight
proc beginFrame*(width, height, pxRatio: float) = export beginFrame
context.beginFrame(width, height, pxRatio) export endFrame
export cancelFrame
proc cancelFrame*() = proc globalCompositeOperation*(context: Context, op: CompositeOperation) =
context.cancelFrame()
proc endFrame*() =
context.endFrame()
proc globalCompositeOperation*(op: CompositeOperation) =
context.globalCompositeOperation(op.cint) context.globalCompositeOperation(op.cint)
proc globalCompositeBlendFunc*(sourceFactor, destFactor: BlendFactor) = proc globalCompositeBlendFunc*(context: Context, sourceFactor, destFactor: BlendFactor) =
context.globalCompositeBlendFunc(sourceFactor.cint, destFactor.cint) context.globalCompositeBlendFunc(sourceFactor.cint, destFactor.cint)
proc globalCompositeBlendFuncSeparate*(srcRGB, destRGB, srcAlpha, destAlpha: BlendFactor) = proc globalCompositeBlendFuncSeparate*(context: Context, srcRGB, destRGB, srcAlpha, destAlpha: BlendFactor) =
context.globalCompositeBlendFuncSeparate(srcRGB.cint, destRGB.cint, srcAlpha.cint, destAlpha.cint) context.globalCompositeBlendFuncSeparate(srcRGB.cint, destRGB.cint, srcAlpha.cint, destAlpha.cint)
template withFrame*(window: View, code: untyped) = template withFrame*(context: Context, window: View, code: untyped) =
let let
winSize = window.size() winSize = window.size()
fbSize = window.frameBufferSize() fbSize = window.frameBufferSize()
pxRatio = cfloat(fbSize.w) / cfloat(winSize.w) pxRatio = cfloat(fbSize.w) / cfloat(winSize.w)
beginFrame(winSize.w.cfloat, winSize.h.cfloat, pxRatio) context.beginFrame(winSize.w.cfloat, winSize.h.cfloat, pxRatio)
code code
endFrame() context.endFrame()
# #
@ -366,98 +359,140 @@ template withFrame*(window: View, code: untyped) =
# The state contains transform, fill and stroke styles, text and font styles, # The state contains transform, fill and stroke styles, text and font styles,
# and scissor clipping. # and scissor clipping.
# #
proc saveState*() = proc saveState*(context: Context, ) =
## Pushes and saves the current render state into a state stack. ## Pushes and saves the current render state into a state stack.
## A matching restoreState() must be used to restore the state. ## A matching restoreState() must be used to restore the state.
context.save() context.save()
proc restoreState*() = proc restoreState*(context: Context, ) =
## Pops and restores current render state. ## Pops and restores current render state.
context.restore() context.restore()
proc resetState*() = proc resetState*(context: Context, ) =
## Resets current render state to default values. Does not affect the render state stack. ## Resets current render state to default values. Does not affect the render state stack.
context.reset() context.reset()
template withState*(code: untyped) = template withState*(context: Context, code: untyped) =
saveState() context.saveState()
try: try:
code code
except: except:
raise raise
finally: finally:
restoreState() context.restoreState()
proc setShapeAntialias*(enabled = true) = proc setShapeAntialias*(context: Context, enabled = true) =
context.shapeAntiAlias(enabled.cint) context.shapeAntiAlias(enabled.cint)
proc setStrokeColor*(color: Color) = proc setStrokeColor*(context: Context, color: Color) =
context.strokeColor(color) context.strokeColor(color)
proc setStrokePaint*(paint: Paint) = proc setStrokePaint*(context: Context, paint: Paint) =
context.strokePaint(paint) context.strokePaint(paint)
proc setFillPaint*(paint: Paint) = proc setFillPaint*(context: Context, paint: Paint) =
context.fillPaint(paint) context.fillPaint(paint)
proc setFillColor*(color: Color) = proc setFillColor*(context: Context, color: Color) =
context.fillColor(color) context.fillColor(color)
proc setFillColor*(r, g, b: uint8) = proc setFillColor*(context: Context, r, g, b: uint8) =
context.fillColor(rgb(r.cuchar, g.cuchar, b.cuchar)) context.fillColor(rgb(r.cuchar, g.cuchar, b.cuchar))
proc setFillColor*(r, g, b: float) = proc setFillColor*(context: Context, r, g, b: float) =
context.fillColor(rgbf(r, g, b)) context.fillColor(rgbf(r, g, b))
proc setFillColor*(r, g, b, a: float) = proc setFillColor*(context: Context, r, g, b, a: float) =
context.fillColor(rgbaf(r, g, b, a)) context.fillColor(rgbaf(r, g, b, a))
proc setFillColor*(r, g, b, a: uint8) = proc setFillColor*(context: Context, r, g, b, a: uint8) =
context.fillColor(rgba(r.cuchar, g.cuchar, b.cuchar, a.cuchar)) context.fillColor(rgba(r.cuchar, g.cuchar, b.cuchar, a.cuchar))
proc setMiterLimit*(limit: float) = proc setMiterLimit*(context: Context, limit: float) =
context.miterLimit(limit) context.miterLimit(limit)
proc setStrokeWidth*(size: float) = proc setStrokeWidth*(context: Context, size: float) =
context.strokeWidth(size) context.strokeWidth(size)
proc setLineCap*(cap: LineCap) = proc setLineCap*(context: Context, cap: LineCap) =
context.lineCap(cap.cint) context.lineCap(cap.cint)
proc setLineJoin*(join: LineJoin) = proc setLineJoin*(context: Context, join: LineJoin) =
context.lineJoin(join.cint) context.lineJoin(join.cint)
proc setGlobalAlpha*(alpha: float) = proc setGlobalAlpha*(context: Context, alpha: float) =
context.globalAlpha(alpha)
proc `shapeAntialias=`*(context: Context, enabled: bool) =
context.shapeAntiAlias(enabled.cint)
proc `strokeColor`*(context: Context, color: Color) =
context.strokeColor(color)
proc `strokePaint=`*(context: Context, paint: Paint) =
context.strokePaint(paint)
proc `fillPaint=`*(context: Context, paint: Paint) =
context.fillPaint(paint)
proc `fillColor=`*(context: Context, color: Color) =
context.fillColor(color)
proc `fillColor=`*(context: Context, color: tuple[r, g, b: uint8]) =
context.fillColor(rgb(color.r.cuchar, color.g.cuchar, color.b.cuchar))
proc `fillColor=`*(context: Context, color: tuple[r, g, b: float]) =
context.fillColor(rgbf(color.r, color.g, color.b))
proc `fillColor=`*(context: Context, color: tuple[r, g, b, a: float]) =
context.fillColor(rgbaf(color.r, color.g, color.b, color.a))
proc setFillColor*(context: Context, color: tuple[r, g, b, a: uint8]) =
context.fillColor(rgba(color.r.cuchar, color.g.cuchar, color.b.cuchar, color.a.cuchar))
proc `miterLimit=`*(context: Context, limit: float) =
context.miterLimit(limit)
proc `strokeWidth=`*(context: Context, size: float) =
context.strokeWidth(size)
proc `lineCap=`*(context: Context, cap: LineCap) =
context.lineCap(cap.cint)
proc `lineJoin=`*(context: Context, join: LineJoin) =
context.lineJoin(join.cint)
proc `globalAlpha=`*(context: Context, alpha: float) =
context.globalAlpha(alpha) context.globalAlpha(alpha)
# Transforms # Transforms
proc resetTransform*() = proc resetTransform*(context: Context) {.inline.} =
context.resetTransform() wrapper.resetTransform(context)
proc transform*(a, b, c, d, e, f: float) = proc transform*(context: Context, a, b, c, d, e, f: float) =
context.transform(a, b, c, d, e, f) wrapper.transform(context, a, b, c, d, e, f)
proc translate*(x, y: float) = proc translate*(context: Context, x, y: float) {.inline.} =
context.translate(x, y) wrapper.translate(context, x, y)
proc rotate*(angle: float) = proc rotate*(context: Context, angle: float) {.inline.} =
context.rotate(angle) wrapper.rotate(context, angle)
proc skewX*(angle: float) = proc skewX*(context: Context, angle: float) {.inline.} =
context.skewX(angle) wrapper.skewX(context, angle)
proc skewY*(angle: float) = proc skewY*(context: Context, angle: float) {.inline.} =
context.skewY(angle) wrapper.skewY(context, angle)
proc scale*(x, y: float) = proc scale*(context: Context, x, y: float) {.inline.} =
context.scale(x, y) wrapper.scale(context, x, y)
proc copyArray[T, U](src: T): U = proc copyArray[T, U](src: T): U =
for i in 0..<src.len: for i in 0..<src.len:
result[i] = type(result[i])((src[i])) result[i] = type(result[i])((src[i]))
proc getCurrentTransform*(): array[6, float] = proc getCurrentTransform*(context: Context, ): array[6, float] =
var res: array[6, cfloat] var res: array[6, cfloat]
context.currentTransform(res[0].addr) context.currentTransform(res[0].addr)
return copyArray[array[6, cfloat], array[6, float]](res) return copyArray[array[6, cfloat], array[6, float]](res)
@ -472,7 +507,7 @@ proc degreesToRadians*(degrees: float): float =
proc radiansToDegrees*(radians: float): float = proc radiansToDegrees*(radians: float): float =
return radToDeg(radians) return radToDeg(radians)
proc createFrameBuffer*(width, height: float, imageFlags: ImageFlagsGL = ImageFlagsGL.NONE): FrameBuffer = proc createFrameBuffer*(context: Context, width, height: float, imageFlags: ImageFlagsGL = ImageFlagsGL.NONE): FrameBuffer =
return context.createFramebuffer(width.cint, height.cint, imageFlags.cint) return context.createFramebuffer(width.cint, height.cint, imageFlags.cint)
proc binde*(fb: FrameBuffer) = proc binde*(fb: FrameBuffer) =
@ -486,111 +521,101 @@ proc delete*(fb: FrameBuffer) =
proc `or`(imageflags1: ImageFlags, imageflags2: ImageFlags): ImageFlags = proc `or`(imageflags1: ImageFlags, imageflags2: ImageFlags): ImageFlags =
return (imageflags1.cint or imageflags2.cint).ImageFlags return (imageflags1.cint or imageflags2.cint).ImageFlags
proc loadImage*(fileName: string, flags: varargs[ImageFlags]): Image = proc loadImage*(context: Context, fileName: string, flags: varargs[ImageFlags]): Image =
var flagArgs = reduce(flags, `or`) var flagArgs = reduce(flags, `or`)
result = context.createImage(fileName, flagArgs.cint) result = context.createImage(fileName, flagArgs.cint)
if result == -1: if result == -1:
raise newException(ImageLoadError, fmt"Could not load image {fileName}.") raise newException(ImageLoadError, fmt"Could not load image {fileName}.")
macro loadImage*(fileName, flags: string): Image = macro loadImage*(context: Context, fileName, flags: string): Image =
return createExpr("ImageFlags", "loadImage", flags, fileName) return createExpr(context, "ImageFlags", "loadImage", flags, fileName)
proc createImageFromArray*(data: openArray[uint8], flags: varargs[ImageFlags]): Image = proc createImageFromArray*(context: Context, data: openArray[uint8], flags: varargs[ImageFlags]): Image =
var flagArgs = reduce(flags, `or`) var flagArgs = reduce(flags, `or`)
result = context.createImageMem(flagArgs.cint, cast[ptr cuchar](data[0].unsafeAddr), data.len.cint) result = context.createImageMem(flagArgs.cint, cast[ptr cuchar](data[0].unsafeAddr), data.len.cint)
if result == -1: if result == -1:
raise newException(ImageLoadError, fmt"Could not load image from data.") raise newException(ImageLoadError, fmt"Could not load image from data.")
proc size*(image: Image): Size = proc size*(context: Context, image: Image): Size =
var rw, rh: cint var rw, rh: cint
context.imageSize(image, rw.addr, rh.addr) context.imageSize(image, rw.addr, rh.addr)
result.width = rw result.width = rw
result.height = rh result.height = rh
proc delete*(image: Image) = export deleteImage
context.deleteImage(image) export beginPath
# Paths proc pathMoveTo*(context: Context, x, y: float) =
proc beginPath*() =
context.beginPath()
proc pathMoveTo*(x, y: float) =
context.moveTo(x, y) context.moveTo(x, y)
proc pathLineTo*(x, y: float) = proc pathLineTo*(context: Context, x, y: float) =
context.lineTo(x, y) context.lineTo(x, y)
proc pathBezierTo*(c1x, c1y, c2x, c2y, x, y: float) = proc pathBezierTo*(context: Context, c1x, c1y, c2x, c2y, x, y: float) =
context.bezierTo(c1x, c1y, c2x, c2y, x, y) context.bezierTo(c1x, c1y, c2x, c2y, x, y)
proc pathQuadTo*(cx, cy, x, y: float) = proc pathQuadTo*(context: Context, cx, cy, x, y: float) =
context.quadTo(cx, cy, x, y) context.quadTo(cx, cy, x, y)
proc pathArcTo*(x1, y1, x2, y2, radius: float) = proc pathArcTo*(context: Context, x1, y1, x2, y2, radius: float) =
context.arcTo(x1, y1, x2, y2, radius) context.arcTo(x1, y1, x2, y2, radius)
proc closePath*() = export closePath
context.closePath()
proc pathWinding*(dir: Winding) = proc pathWinding*(context: Context, dir: Winding) =
context.pathWinding(dir.cint) context.pathWinding(dir.cint)
proc setSolidity*(solidity: Solidity) = proc `solidity=`*(context: Context, solidity: Solidity) =
context.pathWinding(solidity.cint) context.pathWinding(solidity.cint)
proc pathArc*(cx, cy, r, a0, a1: float, dir: int) = proc pathArc*(context: Context, cx, cy, r, a0, a1: float, dir: int) =
context.arc(cx, cy, r, a0, a1, dir.cint) context.arc(cx, cy, r, a0, a1, dir.cint)
proc pathRect*(x, y, width, height: float) = proc pathRect*(context: Context, x, y, width, height: float) =
context.rect(x, y, width, height) context.rect(x, y, width, height)
proc pathRoundedRect*(x, y, width, height, radius: float) = proc pathRoundedRect*(context: Context, x, y, width, height, radius: float) =
context.roundedRect(x, y, width, height, radius) context.roundedRect(x, y, width, height, radius)
proc pathRoundedRectVarying*(x, y, width, height, radiusTopLeft, radiusTopRight, proc pathRoundedRectVarying*(context: Context, x, y, width, height, radiusTopLeft, radiusTopRight,
radiusBottomRight, radiusBottomLeft: float) = radiusBottomRight, radiusBottomLeft: float) =
context.roundedRectVarying( context.roundedRectVarying(
x, y, width, height, x, y, width, height,
radiusTopLeft, radiusTopRight, radiusBottomRight, radiusBottomLeft radiusTopLeft, radiusTopRight, radiusBottomRight, radiusBottomLeft
) )
proc pathEllipse*(cx, cy, radiusX, radiusY: float) = proc pathEllipse*(context: Context, cx, cy, radiusX, radiusY: float) =
context.ellipse(cx, cy, radiusX, radiusY) context.ellipse(cx, cy, radiusX, radiusY)
proc pathCircle*(cx, cy, radius: float) = proc pathCircle*(context: Context, cx, cy, radius: float) =
context.circle(cx, cy, radius) context.circle(cx, cy, radius)
proc pathFill*() = proc pathFill*(context: Context) =
context.fill() context.fill()
proc pathStroke*() = proc pathStroke*(context: Context) =
context.stroke() context.stroke()
proc linearGradient*(startX, startY, endX, endY: float, startColor, endColor: Color): Paint = proc linearGradient*(context: Context, startX, startY, endX, endY: float, startColor, endColor: Color): Paint =
result = context.linearGradient(startX, startY, endX, endY, startColor, endColor) result = wrapper.linearGradient(context, startX, startY, endX, endY, startColor, endColor)
proc boxGradient*(x, y, width, height, radius, feather: float, startColor, endColor: Color): Paint = proc boxGradient*(context: Context, x, y, width, height, radius, feather: float, startColor, endColor: Color): Paint =
result = context.boxGradient(x, y, width, height, radius, feather, startColor, endColor) result = wrapper.boxGradient(context, x, y, width, height, radius, feather, startColor, endColor)
proc radialGradient*(centerX, centerY, innerRadius, outerRadius: float, startColor, endColor: Color): Paint = proc radialGradient*(context: Context, centerX, centerY, innerRadius, outerRadius: float, startColor, endColor: Color): Paint =
result = context.radialGradient(centerX, centerY, innerRadius, outerRadius, startColor, endColor) result = wrapper.radialGradient(context, centerX, centerY, innerRadius, outerRadius, startColor, endColor)
proc imagePattern*(originX, originY, renderSizeX, renderSizeY, angle: float, image: Image, alpha: float): Paint = proc imagePattern*(context: Context, originX, originY, renderSizeX, renderSizeY, angle: float, image: Image, alpha: float): Paint =
result = context.imagePattern(originX, originY, renderSizeX, renderSizeY, angle, image, alpha) result = wrapper.imagePattern(context, originX, originY, renderSizeX, renderSizeY, angle, image, alpha)
proc setScissor*(x, y, width, height: float) = proc setScissor*(context: Context, x, y, width, height: float) =
context.scissor(x, y, width, height) context.scissor(x, y, width, height)
proc intersectScissor*(x, y, width, height: float) = proc intersectScissor*(context: Context, x, y, width, height: float) =
context.intersectScissor(x, y, width, height) context.intersectScissor(x, y, width, height)
proc resetScissor*() = proc resetScissor*(context: Context) =
context.resetScissor() context.resetScissor()
proc cleanup() {.noconv.} =
echo "running cleanup"
context.deleteGL3()
addQuitProc(cleanup)