Add sdl_gpu demo, add more glyph positions and text rendering
This commit is contained in:
parent
458d0ea598
commit
ee2f3065b8
12 changed files with 312 additions and 78 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -1,3 +1,12 @@
|
||||||
|
*
|
||||||
|
!/**/
|
||||||
|
!*.*
|
||||||
|
|
||||||
|
build
|
||||||
|
|
||||||
|
*.out
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
nimcache/
|
nimcache/
|
||||||
|
|
||||||
build/
|
build/
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ proc drawLabel*(text: string, x, y, w, h: float) =
|
||||||
nanovg.setFillColor(1.0, 1.0, 1.0, 1.0)
|
nanovg.setFillColor(1.0, 1.0, 1.0, 1.0)
|
||||||
|
|
||||||
nanovg.textAlign("left middle")
|
nanovg.textAlign("left middle")
|
||||||
nanovg.text(x, y+h*0.5, text)
|
nanovg.text(text, x, y+h*0.5)
|
||||||
|
|
||||||
proc drawWindow*(title: string, x, y, w, h: float) =
|
proc drawWindow*(title: string, x, y, w, h: float) =
|
||||||
let cornerRadius = 3.0
|
let cornerRadius = 3.0
|
||||||
|
|
@ -41,11 +41,11 @@ proc drawWindow*(title: string, x, y, w, h: float) =
|
||||||
|
|
||||||
nanovg.setFontBlur(2)
|
nanovg.setFontBlur(2)
|
||||||
nanovg.setFillColor(RGBA(0,0,0,128))
|
nanovg.setFillColor(RGBA(0,0,0,128))
|
||||||
nanovg.text(x+w/2, y+16+1, title)
|
nanovg.text(title, x+w/2, y+16+1)
|
||||||
|
|
||||||
nanovg.setFontBlur(0)
|
nanovg.setFontBlur(0)
|
||||||
nanovg.setFillColor(RGBA(220,220,220,160))
|
nanovg.setFillColor(RGBA(220,220,220,160))
|
||||||
nanovg.text(x+w/2,y+16, title)
|
nanovg.text(title, x+w/2,y+16)
|
||||||
|
|
||||||
proc isBlack*(color: Color): bool =
|
proc isBlack*(color: Color): bool =
|
||||||
result = true
|
result = true
|
||||||
|
|
@ -163,12 +163,12 @@ proc drawButton*(preicon: string, text: string, x, y, w, h: float, color: Color)
|
||||||
|
|
||||||
nanovg.setFontSize(20.0)
|
nanovg.setFontSize(20.0)
|
||||||
nanovg.setFont("sans-bold")
|
nanovg.setFont("sans-bold")
|
||||||
tb = nanovg.textBounds(0.0, 0.0, text)
|
tb = nanovg.textBounds(text, 0.0, 0.0)
|
||||||
tw = tb.horizontalAdvance
|
tw = tb.horizontalAdvance
|
||||||
|
|
||||||
nanovg.setFontSize(h*0.5)
|
nanovg.setFontSize(h*0.5)
|
||||||
nanovg.setFont("fa")
|
nanovg.setFont("fa")
|
||||||
ib = nanovg.textBounds(0,0, preicon)
|
ib = nanovg.textBounds(preicon, 0, 0)
|
||||||
iw = ib.horizontalAdvance
|
iw = ib.horizontalAdvance
|
||||||
iw += h*0.15
|
iw += h*0.15
|
||||||
|
|
||||||
|
|
@ -176,14 +176,14 @@ proc drawButton*(preicon: string, text: string, x, y, w, h: float, color: Color)
|
||||||
nanovg.setFont("fa")
|
nanovg.setFont("fa")
|
||||||
nanovg.setFillColor(RGBA(255,255,255,96))
|
nanovg.setFillColor(RGBA(255,255,255,96))
|
||||||
nanovg.textAlign("left middle")
|
nanovg.textAlign("left middle")
|
||||||
nanovg.text(x+w*0.5-tw*0.5-iw*0.75, y+h*0.5, preicon)
|
nanovg.text(preicon, x+w*0.5-tw*0.5-iw*0.75, y+h*0.5)
|
||||||
|
|
||||||
nanovg.setFontSize(20.0)
|
nanovg.setFontSize(20.0)
|
||||||
nanovg.setFont("sans-bold")
|
nanovg.setFont("sans-bold")
|
||||||
nanovg.textAlign("left middle")
|
nanovg.textAlign("left middle")
|
||||||
nanovg.setFillColor(RGBA(0,0,0,160))
|
nanovg.setFillColor(RGBA(0,0,0,160))
|
||||||
nanovg.text(x+w*0.5-tw*0.5+iw*0.25, y+h*0.5-1, text)
|
nanovg.text(text, x+w*0.5-tw*0.5+iw*0.25, y+h*0.5-1)
|
||||||
nanovg.setFillColor(RGBA(255,255,255,160))
|
nanovg.setFillColor(RGBA(255,255,255,160))
|
||||||
nanovg.text(x+w*0.5-tw*0.5+iw*0.25, y+h*0.5, text)
|
nanovg.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>".}
|
||||||
|
|
@ -5,7 +5,6 @@ import perf
|
||||||
import common
|
import common
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
glfw.initialize()
|
|
||||||
var c = DefaultOpenglWindowConfig
|
var c = DefaultOpenglWindowConfig
|
||||||
c.version = glv32
|
c.version = glv32
|
||||||
c.title = "Minimal Nim-GLFW example"
|
c.title = "Minimal Nim-GLFW example"
|
||||||
|
|
@ -18,6 +17,7 @@ proc main =
|
||||||
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
|
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
|
||||||
|
|
||||||
|
|
||||||
|
glfw.initialize()
|
||||||
var w = newWindow(c)
|
var w = newWindow(c)
|
||||||
swapInterval(0)
|
swapInterval(0)
|
||||||
setTime(0)
|
setTime(0)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import sdl2/sdl except Color
|
import sdl2/sdl2 as sdl
|
||||||
import sdl2/sdl_image as img, opengl
|
import sdl2/sdl2_image as img, opengl
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import nanovg
|
import nanovg
|
||||||
|
|
@ -13,16 +13,16 @@ proc events(): bool =
|
||||||
while sdl.pollEvent(addr(e)) != 0:
|
while sdl.pollEvent(addr(e)) != 0:
|
||||||
|
|
||||||
# Quit requested
|
# Quit requested
|
||||||
if e.kind == sdl.Quit:
|
if e.kind.EventType == sdl.EventQuit:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Key pressed
|
# Key pressed
|
||||||
elif e.kind == sdl.KeyDown:
|
elif e.kind.EventType == sdl.EventKeyDown:
|
||||||
# Exit on Escape key press
|
# Exit on Escape key press
|
||||||
if e.key.keysym.sym == sdl.K_Escape:
|
if e.key.keysym.sym == sdl.KeycodeEscape:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc frameBufferSize*(window: Window): tuple[w, h: int32] =
|
proc frameBufferSize*(window: ptr Window): tuple[w, h: int32] =
|
||||||
var
|
var
|
||||||
fbWidth: cint
|
fbWidth: cint
|
||||||
fbHeight: cint
|
fbHeight: cint
|
||||||
|
|
@ -31,7 +31,7 @@ proc frameBufferSize*(window: Window): tuple[w, h: int32] =
|
||||||
|
|
||||||
return (fbWidth.int32, fbHeight.int32)
|
return (fbWidth.int32, fbHeight.int32)
|
||||||
|
|
||||||
proc size*(window: Window): tuple[w, h: int32] =
|
proc size*(window: ptr Window): tuple[w, h: int32] =
|
||||||
var
|
var
|
||||||
width: cint
|
width: cint
|
||||||
height: cint
|
height: cint
|
||||||
|
|
@ -45,22 +45,22 @@ proc main() =
|
||||||
fps = newGraph(RenderStyle.FPS, "Frame Time")
|
fps = newGraph(RenderStyle.FPS, "Frame Time")
|
||||||
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
|
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
|
||||||
let
|
let
|
||||||
windowFlags: uint32 = sdl.WINDOW_OPENGL or sdl.WINDOW_ALLOW_HIGHDPI or sdl.WINDOW_SHOWN
|
windowFlags = sdl.WINDOW_OPENGL or sdl.WINDOW_ALLOW_HIGHDPI or sdl.WINDOW_SHOWN
|
||||||
screenWidth = 640
|
screenWidth = 640
|
||||||
screenHeight = 480
|
screenHeight = 480
|
||||||
|
|
||||||
discard sdl.init(sdl.INIT_EVERYTHING)
|
discard sdl.init(sdl.INIT_EVERYTHING.uint32)
|
||||||
|
|
||||||
discard sdl.glSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE.cint)
|
||||||
discard sdl.glSetAttribute(sdl.GL_CONTEXT_FLAGS, sdl.GL_CONTEXT_FORWARD_COMPATIBLE_FLAG)
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_FLAGS, sdl.GL_CONTEXT_FORWARD_COMPATIBLE_FLAG.cint)
|
||||||
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 3)
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 3)
|
||||||
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 2)
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 2)
|
||||||
|
|
||||||
let window = sdl.createWindow(
|
let window = sdl.createWindow(
|
||||||
"SDL2 Test",
|
"SDL2 Test",
|
||||||
sdl.WINDOWPOS_CENTERED,
|
sdl.WINDOWPOS_CENTERED.cint,
|
||||||
sdl.WINDOWPOS_CENTERED,
|
sdl.WINDOWPOS_CENTERED.cint,
|
||||||
screenWidth, screenHeight, windowFlags
|
screenWidth.cint, screenHeight.cint, windowFlags.uint32
|
||||||
)
|
)
|
||||||
|
|
||||||
let context = glCreateContext(window)
|
let context = glCreateContext(window)
|
||||||
|
|
|
||||||
156
examples/demo_sdl2_gpu.nim
Normal file
156
examples/demo_sdl2_gpu.nim
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
import sdl2 as sdl
|
||||||
|
import sdl2/sdl2_gpu as gpu
|
||||||
|
import opengl
|
||||||
|
|
||||||
|
import os
|
||||||
|
import nanovg
|
||||||
|
import perf
|
||||||
|
import common
|
||||||
|
|
||||||
|
proc events(): bool =
|
||||||
|
result = false
|
||||||
|
var e: sdl.Event
|
||||||
|
|
||||||
|
while sdl.pollEvent(addr(e)) != 0:
|
||||||
|
|
||||||
|
# Quit requested
|
||||||
|
if e.kind.EventType == sdl.EventQuit:
|
||||||
|
return true
|
||||||
|
|
||||||
|
# Key pressed
|
||||||
|
elif e.kind.EventType == sdl.EventKeyDown:
|
||||||
|
# Exit on Escape key press
|
||||||
|
if e.key.keysym.sym == sdl.KeycodeEscape:
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc frameBufferSize*(window: ptr Window): tuple[w, h: int32] =
|
||||||
|
var
|
||||||
|
fbWidth: cint
|
||||||
|
fbHeight: cint
|
||||||
|
|
||||||
|
window.glGetDrawableSize(fbWidth.addr, fbHeight.addr)
|
||||||
|
|
||||||
|
return (fbWidth.int32, fbHeight.int32)
|
||||||
|
|
||||||
|
proc size*(window: ptr Window): tuple[w, h: int32] =
|
||||||
|
var
|
||||||
|
width: cint
|
||||||
|
height: cint
|
||||||
|
|
||||||
|
window.getWindowSize(width.addr, height.addr)
|
||||||
|
|
||||||
|
return (width.int32, height.int32)
|
||||||
|
|
||||||
|
template generateFbo(width, height: float, code: untyped): gpu.Image =
|
||||||
|
let fb = createFrameBuffer(width, height, ImageFlagsGL.NO_DELETE)
|
||||||
|
fb.binde()
|
||||||
|
|
||||||
|
glViewPort(0, 0, width.int, height.int)
|
||||||
|
glCullFace(GL_BACK)
|
||||||
|
glFrontFace(GL_CCW)
|
||||||
|
glClearColor(0.3, 0.3, 0.32, 1.0)
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
|
||||||
|
beginFrame(width, height, 1.0)
|
||||||
|
code
|
||||||
|
endFrame()
|
||||||
|
gpu.resetRendererState()
|
||||||
|
echo fb.texture
|
||||||
|
let res = gpu.createImageUsingTexture(cast[TextureHandle](fb.texture), false)
|
||||||
|
fb.delete()
|
||||||
|
res
|
||||||
|
|
||||||
|
proc windowID*(target: ptr Target): uint32 {.
|
||||||
|
cdecl, importc: "GPU_getWindowID".}
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
let
|
||||||
|
fps = newGraph(RenderStyle.FPS, "Frame Time")
|
||||||
|
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
|
||||||
|
|
||||||
|
discard sdl.init(sdl.INIT_EVERYTHING.uint32)
|
||||||
|
discard sdl.glSetAttribute(sdl.GL_STENCIL_SIZE, 1)
|
||||||
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE.cint)
|
||||||
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_FLAGS, sdl.GL_CONTEXT_FORWARD_COMPATIBLE_FLAG.cint)
|
||||||
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MAJOR_VERSION, 3)
|
||||||
|
discard sdl.glSetAttribute(sdl.GL_CONTEXT_MINOR_VERSION, 2)
|
||||||
|
var w, h: cint
|
||||||
|
|
||||||
|
# let
|
||||||
|
# vert = gpu.loadShader(gpu.VERTEX_SHADER, currentSourceDir()/"resources/untextured.vert")
|
||||||
|
# frag = gpu.loadShader(gpu.FRAGMENT_SHADER, currentSourceDir()/"resources/untextured.frag")
|
||||||
|
# program = gpu.linkShaders(vert, frag)
|
||||||
|
|
||||||
|
# glUseProgram(program)
|
||||||
|
|
||||||
|
# let
|
||||||
|
# vertLoc = gpu.getAttributeLocation(program, "gpu_Vertex")
|
||||||
|
# colorLoc = gpu.getAttributeLocation(program, "gpu_Color")
|
||||||
|
# mvpLoc = gpu.getUniformLocation(program, "gpu_ModelViewProjectionMatrix")
|
||||||
|
|
||||||
|
let screen = gpu.initRenderer(gpu.RENDERER_OPENGL_3, 640, 480, sdl.WINDOW_ALLOW_HIGHDPI)
|
||||||
|
gpu.setRequiredFeatures(gpu.FEATURE_BASIC_SHADERS)
|
||||||
|
|
||||||
|
|
||||||
|
nanovg.init()
|
||||||
|
discard sdl.glSetSwapInterval(0)
|
||||||
|
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Regular.ttf", "sans")
|
||||||
|
nanovg.loadFont(currentSourceDir()/"resources/Roboto-Bold.ttf", "sans-bold")
|
||||||
|
nanovg.loadFont(currentSourceDir()/"resources/fa.ttf", "fa")
|
||||||
|
nanovg.loadFont(currentSourceDir()/"resources/entypo.ttf", "icons")
|
||||||
|
|
||||||
|
var done = false
|
||||||
|
var prevt: float = sdl.getTicks().float/1000.0
|
||||||
|
|
||||||
|
var image = gpu.loadImage(currentSourceDir()/"resources/howl.png")
|
||||||
|
|
||||||
|
let window = sdl.getWindowFromID(screen.context.windowID)
|
||||||
|
|
||||||
|
while not done:
|
||||||
|
gpu.clearRGBA(screen, 0, 0, 0, 0xFF)
|
||||||
|
|
||||||
|
# do gpu drawing
|
||||||
|
|
||||||
|
let fbSize = window.frameBufferSize()
|
||||||
|
|
||||||
|
glViewPort(0, 0, fbSize.w, fbSize.h)
|
||||||
|
glCullFace(GL_BACK)
|
||||||
|
glFrontFace(GL_CCW)
|
||||||
|
glClearColor(0.3, 0.3, 0.32, 1.0)
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
|
||||||
|
|
||||||
|
gpu.blit(image, nil, screen, 400, 100)
|
||||||
|
|
||||||
|
gpu.flushBlitBuffer()
|
||||||
|
|
||||||
|
withFrame(window):
|
||||||
|
let x = glyphPositions("Some仮名thing is up", 0, 0, 10)
|
||||||
|
echo x
|
||||||
|
text("Some仮名thing is up", 100, 100, 100)
|
||||||
|
drawWindow("Title", 50, 50, 300, 400)
|
||||||
|
drawLabel("Hello!", 10, 10, 500, 20)
|
||||||
|
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))
|
||||||
|
drawButton("Testing", 100, 300, 160, 28)
|
||||||
|
|
||||||
|
gpu.resetRendererState()
|
||||||
|
|
||||||
|
fps.render(5, 5)
|
||||||
|
cpuGraph.render(210, 5)
|
||||||
|
|
||||||
|
|
||||||
|
gpu.flip(screen)
|
||||||
|
|
||||||
|
let t: float = sdl.getTicks().float/1000.0
|
||||||
|
let dt = t - prevt
|
||||||
|
prevt = t
|
||||||
|
|
||||||
|
let cpuTime: float = sdl.getTicks().float/1000.0 - t
|
||||||
|
|
||||||
|
fps.update(dt)
|
||||||
|
cpuGraph.update(cpuTime)
|
||||||
|
|
||||||
|
done = events()
|
||||||
|
gpu.freeImage(image)
|
||||||
|
gpu.quit()
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
@ -96,7 +96,7 @@ proc render*(graph: PerfGraph, x, y: float) =
|
||||||
nanovg.setFontSize(14)
|
nanovg.setFontSize(14)
|
||||||
nanovg.textAlign("top left")
|
nanovg.textAlign("top left")
|
||||||
nanovg.setFillColor(240, 240, 240, 192)
|
nanovg.setFillColor(240, 240, 240, 192)
|
||||||
nanovg.text(x+3, y+1, graph.name)
|
nanovg.text(graph.name, x+3, y+1)
|
||||||
|
|
||||||
nanovg.setFontSize(18)
|
nanovg.setFontSize(18)
|
||||||
nanovg.textAlign("top right")
|
nanovg.textAlign("top right")
|
||||||
|
|
@ -106,18 +106,18 @@ proc render*(graph: PerfGraph, x, y: float) =
|
||||||
of RenderStyle.FPS:
|
of RenderStyle.FPS:
|
||||||
var str = fmt"{1.0/avg:.2f} FPS"
|
var str = fmt"{1.0/avg:.2f} FPS"
|
||||||
|
|
||||||
nanovg.text(x+width-3, y+1, str)
|
nanovg.text(str, x+width-3, y+1)
|
||||||
nanovg.setFontSize(15)
|
nanovg.setFontSize(15)
|
||||||
nanovg.textAlign("bottom right")
|
nanovg.textAlign("bottom right")
|
||||||
nanovg.setFillColor(240, 240, 240, 160)
|
nanovg.setFillColor(240, 240, 240, 160)
|
||||||
|
|
||||||
str = fmt"{avg*1000:.2f} ms"
|
str = fmt"{avg*1000:.2f} ms"
|
||||||
nanovg.text(x+width-3, y+height-1, str)
|
nanovg.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(x+width-3, y+1, str)
|
nanovg.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(x+width-3, y+1, str)
|
nanovg.text(str, x+width-3, y+1)
|
||||||
|
|
|
||||||
BIN
examples/resources/howl.png
Normal file
BIN
examples/resources/howl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
examples/resources/umeboshi.ttf
Normal file
BIN
examples/resources/umeboshi.ttf
Normal file
Binary file not shown.
|
|
@ -8,12 +8,12 @@ srcDir = "src"
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 1.0.0",
|
requires "nim >= 1.0.6",
|
||||||
"nimterop#head",
|
"nimterop#head",
|
||||||
"regex >= 0.12.0",
|
"regex >= 0.12.0",
|
||||||
"opengl >= 1.2.2",
|
"opengl >= 1.2.2",
|
||||||
"nim-glfw#head",
|
"nim-glfw#head",
|
||||||
"sdl2_nim >= 2.0.12.0"
|
"sdl2"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
@ -56,6 +56,10 @@ task buildSDL2ExampleDebug, "Build SDL2 example debug":
|
||||||
let buildDir = setupSDL2()
|
let buildDir = setupSDL2()
|
||||||
exec "nimble c --app:gui --debugger:native -o:" & buildDir & "/" & "demo_sdl2_debug".toExe & " -r examples/demo_sdl2.nim"
|
exec "nimble c --app:gui --debugger:native -o:" & buildDir & "/" & "demo_sdl2_debug".toExe & " -r examples/demo_sdl2.nim"
|
||||||
|
|
||||||
|
task buildSDL2GPUExample, "Build SDL2 GPU example":
|
||||||
|
let buildDir = setupSDL2()
|
||||||
|
exec "nimble c --app:gui --debugger:native -o:" & buildDir & "/" & "demo_sdl2_gpu".toExe & " -r examples/demo_sdl2_gpu.nim"
|
||||||
|
|
||||||
task buildGLFWExample, "Build GLFW example":
|
task buildGLFWExample, "Build GLFW example":
|
||||||
let buildDir = setupGLFW()
|
let buildDir = setupGLFW()
|
||||||
exec "nimble c --app:gui -d:useGlfw -d:release -d:danger -o:" & buildDir & "/" & "demo_glfw".toExe & " -r examples/demo.nim"
|
exec "nimble c --app:gui -d:useGlfw -d:release -d:danger -o:" & buildDir & "/" & "demo_glfw".toExe & " -r examples/demo.nim"
|
||||||
|
|
|
||||||
12
nim.cfg
12
nim.cfg
|
|
@ -1,4 +1,14 @@
|
||||||
@if useGlfw:
|
@if useGlfw:
|
||||||
-d:glfwStaticLib
|
-d:glfwStaticLib
|
||||||
@end
|
@end
|
||||||
-d:useGlew
|
-d:useGlew
|
||||||
|
-d:nanovg_Git
|
||||||
|
-d:nanovg_setver="1f9c8864fc556a1be4d4bf1d6bfe20cde25734b4"
|
||||||
|
-d:nanovg_Static
|
||||||
|
-d:SDL_SetVer="2.0.12" -d:SDL_DL -d:SDL_Static
|
||||||
|
-d:SDL_ImageSetVer="2.0.5" -d:SDL_Image_DL -d:SDL_Image_Static
|
||||||
|
-d:SDL_NetSetVer="2.0.1" -d:SDL_Net_DL -d:SDL_Net_Static
|
||||||
|
-d:SDL_MixerSetVer="2.0.4" -d:SDL_Mixer_DL -d:SDL_Mixer_Static
|
||||||
|
-d:SDL_ttf_SetVer="2.0.15" -d:SDL_TTF_DL -d:SDL_ttf_Static
|
||||||
|
-d:SDL_GpuSetVer="def5ea1" -d:SDL_GPU_Git -d:SDL_Gpu_Static
|
||||||
|
-d:SDL2_GFXPrimitivesSetVer="1.0.4" -d:SDL2_GFXPrimitives_DL -d:SDL2_GFXPrimitives_Static -d:SDL2_GFX_Static
|
||||||
|
|
@ -21,9 +21,9 @@ export TransRGBAf
|
||||||
#{.experimental: "dynamicBindSym".}
|
#{.experimental: "dynamicBindSym".}
|
||||||
|
|
||||||
type
|
type
|
||||||
FontLoadError* = object of Exception
|
FontLoadError* = object of CatchableError
|
||||||
ImageLoadError* = object of Exception
|
ImageLoadError* = object of CatchableError
|
||||||
ContextInitError* = object of Exception
|
ContextInitError* = object of CatchableError
|
||||||
Context = ptr NVGContext
|
Context = ptr NVGContext
|
||||||
|
|
||||||
Alignment* {.size: sizeof(cint), pure.} = enum
|
Alignment* {.size: sizeof(cint), pure.} = enum
|
||||||
|
|
@ -92,7 +92,13 @@ type
|
||||||
|
|
||||||
TextRow* = tuple[x, y, minX, maxX, height: float]
|
TextRow* = tuple[x, y, minX, maxX, height: float]
|
||||||
|
|
||||||
ImageFlags* {.size: sizeof(cint).} = enum
|
FrameBuffer* = ptr NVGLUframebuffer
|
||||||
|
|
||||||
|
ImageFlagsGL* {.size: sizeof(cint), pure.} = enum
|
||||||
|
NONE = 0,
|
||||||
|
NO_DELETE = NVG_IMAGE_NODELETE
|
||||||
|
|
||||||
|
ImageFlags* {.size: sizeof(cint), pure.} = enum
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
GENERATE_MIPMAPS = NVG_IMAGE_GENERATE_MIPMAPS, ## Generate mipmaps during creation of the image.
|
GENERATE_MIPMAPS = NVG_IMAGE_GENERATE_MIPMAPS, ## Generate mipmaps during creation of the image.
|
||||||
REPEATX = NVG_IMAGE_REPEATX, ## Repeat image in X direction.
|
REPEATX = NVG_IMAGE_REPEATX, ## Repeat image in X direction.
|
||||||
|
|
@ -206,24 +212,24 @@ proc textAlign*(alignments: varargs[Alignment]) =
|
||||||
macro textAlign*(descriptor: string) =
|
macro textAlign*(descriptor: string) =
|
||||||
result = createExpr("Alignment", "textAlign", descriptor)
|
result = createExpr("Alignment", "textAlign", descriptor)
|
||||||
|
|
||||||
proc textBounds*(x, y: float, text: string): TextBounds =
|
proc textBounds*(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*(x, y: float, content: string) =
|
proc text*(text: string, x, y: float) =
|
||||||
discard context.Text(x, y, content, nil)
|
discard context.Text(x, y, text, nil)
|
||||||
|
|
||||||
proc textBoxBounds*(x, y, breakRowWidth: float, text: string): Bounds =
|
proc textBoxBounds*(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*(x, y, breakRowWidth: float, content: string) =
|
proc textBox*(text: string, x, y, breakRowWidth: float) =
|
||||||
context.TextBox(x, y, breakRowWidth, content, nil)
|
context.TextBox(x, y, breakRowWidth, text, nil)
|
||||||
|
|
||||||
proc textMetrics*(): TextMetrics =
|
proc textMetrics*(): TextMetrics =
|
||||||
var
|
var
|
||||||
|
|
@ -233,8 +239,7 @@ proc textMetrics*(): TextMetrics =
|
||||||
|
|
||||||
return (ascender.float, descender.float, lineHeight.float)
|
return (ascender.float, descender.float, lineHeight.float)
|
||||||
|
|
||||||
# TODO Continue with TextGlyphPos
|
iterator glyphPositions(start: cstring, endPos: cstring, x, y: float): GlyphPosition =
|
||||||
proc glyphPositions*(text: string, x, y: float): seq[GlyphPosition] =
|
|
||||||
const maxPositions = 100
|
const maxPositions = 100
|
||||||
var
|
var
|
||||||
positions: array[maxPositions, NVGglyphPosition]
|
positions: array[maxPositions, NVGglyphPosition]
|
||||||
|
|
@ -244,11 +249,11 @@ proc glyphPositions*(text: string, x, y: float): seq[GlyphPosition] =
|
||||||
strIndex = 0
|
strIndex = 0
|
||||||
lineHeight = textMetrics().lineHeight
|
lineHeight = textMetrics().lineHeight
|
||||||
|
|
||||||
result = newSeqOfCap[GlyphPosition](maxPositions)
|
let strLen = cast[ByteAddress](endPos) - cast[ByteAddress](start)
|
||||||
|
|
||||||
while (strIndex < text.len):
|
while (strIndex < strLen):
|
||||||
numGlyphs = context.TextGlyphPositions(
|
numGlyphs = context.TextGlyphPositions(
|
||||||
lastX, y, cast[cstring](text[strIndex].unsafeAddr), nil,
|
lastX, y, cast[cstring](start[strIndex].unsafeAddr), endPos,
|
||||||
positions[0].addr, maxPositions
|
positions[0].addr, maxPositions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -264,29 +269,66 @@ proc glyphPositions*(text: string, x, y: float): seq[GlyphPosition] =
|
||||||
|
|
||||||
byteWidth = nextBaddr - baddr
|
byteWidth = nextBaddr - baddr
|
||||||
elif i == (numGlyphs - 1):
|
elif i == (numGlyphs - 1):
|
||||||
byteWidth = len(text) - bytesProcessed
|
byteWidth = strLen - bytesProcessed
|
||||||
|
|
||||||
var glyph = newStringOfCap(byteWidth)
|
var glyph = newStringOfCap(byteWidth)
|
||||||
for j in 0..<byteWidth:
|
for j in 0..<byteWidth:
|
||||||
glyph.add(retPos.str[j])
|
glyph.add(retPos.str[j])
|
||||||
|
|
||||||
let pos = GlyphPosition(
|
yield GlyphPosition(
|
||||||
glyph: glyph, x: retPos.x, y: y, minX: retPos.minX, maxX: retPos.maxX,
|
glyph: glyph, x: retPos.x, y: y, minX: retPos.minX, maxX: retPos.maxX,
|
||||||
height: lineHeight
|
height: lineHeight
|
||||||
)
|
)
|
||||||
|
|
||||||
result.add(pos)
|
|
||||||
bytesProcessed += byteWidth
|
bytesProcessed += byteWidth
|
||||||
|
|
||||||
lastX = positions[numGlyphs-1].x
|
lastX = positions[numGlyphs-1].x
|
||||||
strIndex += maxPositions
|
strIndex += maxPositions
|
||||||
|
|
||||||
proc glyphPositions*(text: string, x, y, maxWidth: float): seq[GlyphPosition] =
|
proc glyphPositions*(text: string, x, y: float): seq[GlyphPosition] =
|
||||||
const maxRows = 100
|
result = newSeqOfCap[GlyphPosition](100)
|
||||||
|
for gpos in glyphPositions(cast[cstring](text[0].unsafeAddr), nil, x, y):
|
||||||
|
result.add gpos
|
||||||
|
|
||||||
|
proc glyphPositions*(row: NVGtextRow, x, y: float): seq[GlyphPosition] =
|
||||||
|
result = newSeqOfCap[GlyphPosition](100)
|
||||||
|
for gpos in glyphPositions(row.start, row.`end`, x, y):
|
||||||
|
result.add gpos
|
||||||
|
|
||||||
|
iterator textRows(text: string, x, y, maxWidth: float): NVGtextRow =
|
||||||
|
const maxRows = 10
|
||||||
var
|
var
|
||||||
rows: array[maxRows, NVGtextRow]
|
rows: array[maxRows, NVGtextRow]
|
||||||
|
numRows: int
|
||||||
|
start = cast[cstring](text[0].unsafeAddr)
|
||||||
|
|
||||||
|
while true:
|
||||||
|
numRows = context.TextBreakLines(
|
||||||
|
start,
|
||||||
|
nil,
|
||||||
|
maxWidth, rows[0].addr, maxRows
|
||||||
|
)
|
||||||
|
if numRows == 0:
|
||||||
|
break
|
||||||
|
for i in 0 ..< numRows:
|
||||||
|
yield rows[i]
|
||||||
|
|
||||||
|
start = rows[numRows-1].next
|
||||||
|
|
||||||
|
proc glyphPositions*(text: string, x, y, maxWidth: float): seq[GlyphPosition] =
|
||||||
|
var newY = y
|
||||||
|
|
||||||
|
for row in textRows(text, x, y, maxWidth):
|
||||||
|
let glyphPositions = row.glyphPositions(x, newY)
|
||||||
|
result.add(glyphPositions)
|
||||||
|
newY += glyphPositions[0].height
|
||||||
|
|
||||||
|
proc text*(text: string, x, y, maxWidth: float) =
|
||||||
|
var newY = y
|
||||||
|
|
||||||
|
for row in textRows(text, x, y, maxWidth):
|
||||||
|
discard context.Text(x, newY, row.start, row.`end`)
|
||||||
|
newY += textMetrics().lineHeight
|
||||||
|
|
||||||
proc beginFrame*(width, height, pxRatio: float) =
|
proc beginFrame*(width, height, pxRatio: float) =
|
||||||
context.BeginFrame(width, height, pxRatio)
|
context.BeginFrame(width, height, pxRatio)
|
||||||
|
|
@ -424,13 +466,21 @@ proc setTransformIdentity*(dest: array[6, float]) =
|
||||||
var dst = copyArray[array[6, float], array[6, cfloat]](dest)
|
var dst = copyArray[array[6, float], array[6, cfloat]](dest)
|
||||||
TransformIdentity(dst[0].addr)
|
TransformIdentity(dst[0].addr)
|
||||||
|
|
||||||
|
|
||||||
proc degreesToRadians*(degrees: float): float =
|
proc degreesToRadians*(degrees: float): float =
|
||||||
return DegToRad(degrees)
|
return DegToRad(degrees)
|
||||||
|
|
||||||
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 =
|
||||||
|
return context.CreateFramebuffer(width.cint, height.cint, imageFlags.cint)
|
||||||
|
|
||||||
|
proc binde*(fb: FrameBuffer) =
|
||||||
|
BindFramebuffer(fb)
|
||||||
|
|
||||||
|
proc delete*(fb: FrameBuffer) =
|
||||||
|
fb.DeleteFramebuffer()
|
||||||
|
|
||||||
# Images
|
# Images
|
||||||
|
|
||||||
proc `or`(imageflags1: ImageFlags, imageflags2: ImageFlags): ImageFlags =
|
proc `or`(imageflags1: ImageFlags, imageflags2: ImageFlags): ImageFlags =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import opengl
|
import opengl
|
||||||
import regex
|
import strutils
|
||||||
|
|
||||||
import nimterop/[cimport, build]
|
import nimterop/[cimport, build]
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ src/*.c
|
||||||
|
|
||||||
let contents = readFile(srcDir/"src/nanovg_gl.h")
|
let contents = readFile(srcDir/"src/nanovg_gl.h")
|
||||||
when defined(useGlfw):
|
when defined(useGlfw):
|
||||||
let newContents = contents.replace(re"#define NANOVG_GL_H", """
|
let newContents = contents.replace("#define NANOVG_GL_H", """
|
||||||
#define NANOVG_GL_H
|
#define NANOVG_GL_H
|
||||||
#define NANOVG_GL_USE_UNIFORMBUFFER
|
#define NANOVG_GL_USE_UNIFORMBUFFER
|
||||||
#define NANOVG_GL3
|
#define NANOVG_GL3
|
||||||
|
|
@ -39,30 +39,33 @@ src/*.c
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include "nanovg.h"
|
#include "nanovg.h"
|
||||||
""", limit=1)
|
""")
|
||||||
else:
|
else:
|
||||||
let newContents = contents.replace(re"#define NANOVG_GL_H", """
|
let newContents = contents.replace("#define NANOVG_GL_H", """
|
||||||
#define NANOVG_GL_H
|
#define NANOVG_GL_H
|
||||||
#define NANOVG_GL_USE_UNIFORMBUFFER
|
#define NANOVG_GL_USE_UNIFORMBUFFER
|
||||||
#define NANOVG_GL3
|
#define NANOVG_GL3
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "nanovg.h"
|
#include "nanovg.h"
|
||||||
""", limit=1)
|
""")
|
||||||
|
|
||||||
writeFile(srcDir/"src/nanovg_gl.h", newContents)
|
writeFile(srcDir/"src/nanovg_gl.h", newContents)
|
||||||
|
# This is needed for some function definitions inside nanovg_gl.h
|
||||||
|
writeFile(srcDir/"src/nanovg_gl.c", newContents)
|
||||||
|
|
||||||
cDefine("NANOVG_GL3_IMPLEMENTATION", "")
|
cDefine("NANOVG_GL3_IMPLEMENTATION", "")
|
||||||
|
cDefine("NANOVG_GL3", "")
|
||||||
|
|
||||||
# Manually wrap any symbols since nimterop cannot or incorrectly wraps them
|
# Manually wrap any symbols since nimterop cannot or incorrectly wraps them
|
||||||
cOverride:
|
cOverride:
|
||||||
# Standard Nim code to wrap types, consts, procs, etc.
|
# Standard Nim code to wrap types, consts, procs, etc.
|
||||||
type
|
type
|
||||||
NVGcontext* {.importc: "struct NVGcontext", bycopy.} = object
|
NVGcontext* {.bycopy.} = object
|
||||||
NVGcolor* {.importc: "struct NVGcolor", bycopy.} = object
|
NVGcolor* {.bycopy.} = object
|
||||||
r* {.importc: "r".}: cfloat
|
r*: cfloat
|
||||||
g* {.importc: "g".}: cfloat
|
g*: cfloat
|
||||||
b* {.importc: "b".}: cfloat
|
b*: cfloat
|
||||||
a* {.importc: "a".}: cfloat
|
a*: cfloat
|
||||||
|
|
||||||
# Specify include directories for gcc and Nim
|
# Specify include directories for gcc and Nim
|
||||||
cIncludeDir(srcDir/"src")
|
cIncludeDir(srcDir/"src")
|
||||||
|
|
@ -71,11 +74,14 @@ cIncludeDir(srcDir/"src")
|
||||||
when defined(macosx):
|
when defined(macosx):
|
||||||
# cDefine("GLFW_INCLUDE_GLCOREARB", "1")
|
# cDefine("GLFW_INCLUDE_GLCOREARB", "1")
|
||||||
when defined(useGlfw):
|
when defined(useGlfw):
|
||||||
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW -D_GLFW_USE_RETINA -D_GLFW_COCOA -D_GLFW_USE_CHDir -D_GLFW_USE_MENUBAR".}
|
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW -D_GLFW_USE_RETINA -D_GLFW_COCOA -D_GLFW_USE_CHDir -D_GLFW_USE_MENUBAR -Bstatic".}
|
||||||
{.passL: "-m64 -lglew -framework GLUT -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework Carbon -lm".}
|
#{.passL: "/usr/local/lib/libSDL2_gpu.a -m64 -lglew -framework GLUT -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework Carbon -lm".}
|
||||||
else:
|
else:
|
||||||
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW".}
|
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW".}
|
||||||
{.passL: "-m64 -lglew -framework GLUT -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework Carbon -lm".}
|
when defined(nanovg_Static):
|
||||||
|
{.passL: "-m64 -lglew -framework GLUT -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework Carbon -framework CoreAudio -lm".}
|
||||||
|
else:
|
||||||
|
{.passL: "-m64 -lSDL2 -framework GLUT -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework Carbon -framework CoreAudio -lm".}
|
||||||
|
|
||||||
elif defined(unix):
|
elif defined(unix):
|
||||||
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW".}
|
{.passC: "-DNANOVG_GL3_IMPLEMENTATION -DNANOVG_GLEW".}
|
||||||
|
|
@ -107,21 +113,20 @@ cPlugin:
|
||||||
# Symbol renaming examples
|
# Symbol renaming examples
|
||||||
proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} =
|
proc onSymbol*(sym: var Symbol) {.exportc, dynlib.} =
|
||||||
# Get rid of leading and trailing underscores
|
# Get rid of leading and trailing underscores
|
||||||
# sym.name = sym.name.strip(chars = {'_'})
|
sym.name = sym.name.strip(chars = {'_'})
|
||||||
|
|
||||||
# Remove prefixes or suffixes from procs
|
# Remove prefixes or suffixes from procs
|
||||||
if sym.name.startsWith("nvg__"):
|
sym.name = sym.name.replace(re"^nvg__", "")
|
||||||
sym.name = sym.name.replace(re"nvg__", "")
|
|
||||||
|
|
||||||
if sym.kind == nskProc:
|
if sym.kind == nskProc:
|
||||||
sym.name = sym.name.replace(re"glnvg__", "")
|
sym.name = sym.name.replace(re"^glnvg__", "")
|
||||||
sym.name = sym.name.replace(re"nvg__", "")
|
sym.name = sym.name.replace(re"^nvg__", "")
|
||||||
sym.name = sym.name.replace(re"nvglu", "")
|
sym.name = sym.name.replace(re"^nvglu", "")
|
||||||
sym.name = sym.name.replace(re"nvgl", "")
|
sym.name = sym.name.replace(re"^nvgl", "")
|
||||||
sym.name = sym.name.replace(re"nvg", "")
|
sym.name = sym.name.replace(re"^nvg", "")
|
||||||
|
|
||||||
# Finally import wrapped header file. Recurse if #include files should also
|
# Finally import wrapped header file. Recurse if #include files should also
|
||||||
# be wrapped. Set dynlib if binding to dynamic library.
|
# be wrapped. Set dynlib if binding to dynamic library.
|
||||||
cImport(srcDir/"src/nanovg.h")
|
cImport(srcDir/"src/nanovg.h", flags = "-f=ast2")
|
||||||
cImport(srcDir/"src/nanovg_gl.h")
|
cImport(srcDir/"src/nanovg_gl.h", flags = "-f=ast2")
|
||||||
cImport(srcDir/"src/nanovg_gl_utils.h")
|
cImport(srcDir/"src/nanovg_gl_utils.h", flags = "-f=ast2")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue