Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ nimbledeps
/examples/emscripten/*.data
/examples/emscripten/*.html
!/examples/emscripten/emscripten.html
/examples/*.js
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ For a complete working example (window + GL context + render loop), see:
- `examples/opengl_windy_renderlist.nim`
- `examples/sdl2_renderlist.nim`

For a Nim JS + WebGL example (no Windy), see:

- `examples/webgl_renderlist.nim` (paired with `examples/webgl_renderlist.html`)

## Run Tests

Runs all tests + compiles all examples listed in `config.nims`:
Expand Down
2 changes: 2 additions & 0 deletions config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ task test, "run unit test":
exec("nim c examples/opengl_windy_text.nim")
exec("nim c examples/sdl2_renderlist.nim")
exec("nim c examples/sdl2_renderlist_100.nim")
exec("nim js examples/webgl_renderlist.nim")
exec("nim js examples/webgl_renderlist_100.nim")

task emscripten, "build emscripten examples":
exec("nim c -d:emscripten examples/opengl_windy_renderlist.nim")
Expand Down
22 changes: 22 additions & 0 deletions examples/webgl_renderlist.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FigDraw WebGL RenderList (Nim JS)</title>
<style>
html, body {
margin: 0;
height: 100%;
background: #0c0f16;
}
canvas {
display: block;
}
</style>
</head>
<body>
<!-- Build with: nim js -d:release --out:examples/webgl_renderlist.js examples/webgl_renderlist.nim -->
<script src="webgl_renderlist.js"></script>
</body>
</html>
124 changes: 124 additions & 0 deletions examples/webgl_renderlist.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
when not defined(js) and not defined(nimsuggest):
{.fatal: "This example requires the Nim JS backend (nim js).".}

import std/[dom, jsconsole, jsffi]
import chroma

import figdraw/commons
import figdraw/fignodes
import figdraw/opengl/renderer as glrenderer
import figdraw/opengl/glapi
import figdraw/utils/glutils
import figdraw/webgl/api as webgl

proc makeRenderTree*(w, h: float32): Renders =
var list = RenderList()

let rootIdx = list.addRoot(Fig(
kind: nkRectangle,
childCount: 0,
zlevel: 0.ZLevel,
screenBox: rect(0, 0, w, h),
fill: rgba(255, 255, 255, 255).color,
))

list.addChild(rootIdx, Fig(
kind: nkRectangle,
childCount: 0,
zlevel: 0.ZLevel,
corners: [10.0'f32, 20.0, 30.0, 40.0],
screenBox: rect(60, 60, 220, 140),
fill: rgba(220, 40, 40, 255).color,
stroke: RenderStroke(weight: 5.0, color: rgba(0, 0, 0, 255).color)
))
list.addChild(rootIdx, Fig(
kind: nkRectangle,
childCount: 0,
zlevel: 0.ZLevel,
screenBox: rect(320, 120, 220, 140),
fill: rgba(40, 180, 90, 255).color,
shadows: [
RenderShadow(
style: DropShadow,
blur: 10,
spread: 10,
x: 10,
y: 10,
color: rgba(0, 0, 0, 55).color,
),
RenderShadow(),
RenderShadow(),
RenderShadow(),
],
))
list.addChild(rootIdx, Fig(
kind: nkRectangle,
childCount: 0,
zlevel: 0.ZLevel,
screenBox: rect(180, 300, 220, 140),
fill: rgba(60, 90, 220, 255).color,
))

result = Renders(layers: initOrderedTable[ZLevel, RenderList]())
result.layers[0.ZLevel] = list

proc main() =
app.running = true
app.autoUiScale = false
app.uiScale = 1.0

let canvas = webgl.asCanvas(document.createElement("canvas"))
document.body.appendChild(canvas)

document.body.style.margin = "0"
document.body.style.overflow = "hidden"
document.body.style.background = "#0c0f16"
canvas.style.display = "block"

let gl = cast[glapi.WebGL2RenderingContext](canvas.getContext("webgl2"))
if gl.isNull or gl.isUndefined:
console.error("WebGL2 not available")
return

setWebGLContext(gl)
startOpenGL(openglVersion)

let renderer = glrenderer.newOpenGLRenderer(
atlasSize = 192,
pixelScale = 1.0,
)

var lastCssSize = vec2(0.0'f32, 0.0'f32)
var renders = makeRenderTree(0.0'f32, 0.0'f32)

proc resizeAndRender() =
let dpr = if window.devicePixelRatio <= 0: 1.0 else: window.devicePixelRatio
let cssWidth = max(window.innerWidth, 1)
let cssHeight = max(window.innerHeight, 1)

app.pixelScale = dpr.float32
renderer.ctx.pixelScale = app.pixelScale

canvas.width = int(cssWidth.float * dpr)
canvas.height = int(cssHeight.float * dpr)
canvas.style.width = cstring($cssWidth & "px")
canvas.style.height = cstring($cssHeight & "px")

let cssSize = vec2(cssWidth.float32, cssHeight.float32)
if cssSize != lastCssSize:
lastCssSize = cssSize
renders = makeRenderTree(cssSize.x, cssSize.y)

renderer.renderFrame(
renders,
vec2(canvas.width.float32, canvas.height.float32),
)

proc onResize(e: Event) =
resizeAndRender()

window.addEventListener("resize", onResize)
resizeAndRender()

when isMainModule:
main()
22 changes: 22 additions & 0 deletions examples/webgl_renderlist_100.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FigDraw WebGL RenderList 100 (Nim JS)</title>
<style>
html, body {
margin: 0;
height: 100%;
background: #0c0f16;
}
canvas {
display: block;
}
</style>
</head>
<body>
<!-- Build with: nim js -d:release --out:examples/webgl_renderlist_100.js examples/webgl_renderlist_100.nim -->
<script src="webgl_renderlist_100.js"></script>
</body>
</html>
125 changes: 125 additions & 0 deletions examples/webgl_renderlist_100.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
when not defined(js) and not defined(nimsuggest):
{.fatal: "This example requires the Nim JS backend (nim js).".}

import std/[dom, jsconsole, jsffi, strutils]

import figdraw/commons
import figdraw/fignodes
import figdraw/opengl/renderer as glrenderer
import figdraw/opengl/glapi
import figdraw/utils/glutils
import figdraw/webgl/api as webgl

import renderlist_100_common

var globalFrame = 0

proc main() =
app.running = true
app.autoUiScale = false
app.uiScale = 1.0
app.pixelScale = 1.0

let canvas = webgl.asCanvas(document.createElement("canvas"))

document.body.style.margin = "0"
document.body.style.overflow = "hidden"
document.body.style.background = "#0c0f16"
document.body.style.height = "100%"

let root = document.createElement("div")
root.style.position = "relative"
root.style.width = "100%"
root.style.height = "100%"
root.style.overflow = "hidden"
document.body.appendChild(root)

canvas.style.display = "block"
canvas.style.position = "absolute"
canvas.style.left = "0"
canvas.style.top = "0"
root.appendChild(canvas)

let textLayer = document.createElement("div")
textLayer.style.position = "absolute"
textLayer.style.left = "0"
textLayer.style.top = "0"
textLayer.style.width = "100%"
textLayer.style.height = "100%"
textLayer.style.pointerEvents = "none"
textLayer.style.zIndex = "2"
root.appendChild(textLayer)

let fpsNode = document.createElement("div")
fpsNode.style.position = "absolute"
fpsNode.style.left = "12px"
fpsNode.style.top = "10px"
fpsNode.style.padding = "4px 6px"
fpsNode.style.borderRadius = "6px"
fpsNode.style.color = "#cfe2ff"
fpsNode.style.background = "rgba(12, 15, 22, 0.55)"
fpsNode.style.fontFamily =
"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
fpsNode.style.fontSize = "12px"
fpsNode.style.letterSpacing = "0.3px"
fpsNode.textContent = "FPS: --"
textLayer.appendChild(fpsNode)

let gl = cast[glapi.WebGL2RenderingContext](canvas.getContext("webgl2"))
if gl.isNull or gl.isUndefined:
console.error("WebGL2 not available")
return

setWebGLContext(gl)
startOpenGL(openglVersion)

let renderer = glrenderer.newOpenGLRenderer(
atlasSize = when not defined(useFigDrawTextures): 1024 else: 2048,
pixelScale = app.pixelScale,
)

proc updateCanvas(): Vec2 =
let dpr = if window.devicePixelRatio <= 0: 1.0 else: window.devicePixelRatio
let cssWidth = max(window.innerWidth, 1)
let cssHeight = max(window.innerHeight, 1)

app.pixelScale = dpr.float32
renderer.ctx.pixelScale = app.pixelScale

let pixelWidth = int(cssWidth.float * dpr)
let pixelHeight = int(cssHeight.float * dpr)
if canvas.width != pixelWidth:
canvas.width = pixelWidth
if canvas.height != pixelHeight:
canvas.height = pixelHeight
canvas.style.width = cstring($cssWidth & "px")
canvas.style.height = cstring($cssHeight & "px")

result = vec2(cssWidth.float32, cssHeight.float32)

var fpsLastTime = 0.0
var fpsFrames = 0

proc drawFrame(time: float) =
inc globalFrame
let cssSize = updateCanvas()
var renders = makeRenderTree(cssSize.x, cssSize.y, globalFrame)
renderer.renderFrame(
renders,
vec2(canvas.width.float32, canvas.height.float32),
)
inc fpsFrames
if fpsLastTime == 0.0:
fpsLastTime = time
let elapsed = time - fpsLastTime
if elapsed >= 500.0:
let fps = fpsFrames.float * 1000.0 / elapsed
fpsNode.textContent = cstring("FPS: " & formatFloat(fps, ffDecimal, 1))
fpsFrames = 0
fpsLastTime = time
discard window.requestAnimationFrame(drawFrame)

discard window.requestAnimationFrame(drawFrame)

when isMainModule:
main()
2 changes: 1 addition & 1 deletion src/figdraw/common/fontutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import std/isolation
import pkg/vmath
import pkg/pixie
import pkg/pixie/fonts
import pkg/chronicles
import ../utils/logging

import ./rchannels
import ./imgutils
Expand Down
28 changes: 28 additions & 0 deletions src/figdraw/common/fontutils_js.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import fonttypes
import uimaths

type TypeFaceKinds* = enum
TTF
OTF
SVG

type Box* = Rect

proc getTypefaceImpl*(name: string): FontId =
FontId(0)

proc getTypefaceImpl*(name, data: string, kind: TypeFaceKinds): FontId =
FontId(0)

proc getLineHeightImpl*(font: UiFont): float32 =
0.0

proc getTypesetImpl*(
box: Box,
spans: openArray[(UiFont, string)],
hAlign = Left,
vAlign = Top,
minContent = false,
wrap = true,
): GlyphArrangement =
GlyphArrangement()
2 changes: 1 addition & 1 deletion src/figdraw/common/imgutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import std/[isolation, locks, times]
import pkg/vmath
import pkg/pixie
import pkg/pixie/fonts
import chronicles
import ../utils/logging

import ./rchannels
import ./formatflippy
Expand Down
28 changes: 28 additions & 0 deletions src/figdraw/common/imgutils_js.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import std/hashes

type
ImageId* = distinct Hash

ImgObj* = object
id*: ImageId

ImageChannel* = object

var imageChan* = ImageChannel()

proc `==`*(a, b: ImageId): bool {.borrow.}

proc imgId*(name: string): ImageId =
hash(name).ImageId

proc tryRecv*(ch: ImageChannel; msg: var ImgObj): bool =
false

proc hasImage*(id: ImageId): bool =
false

proc loadImage*(filePath: string): ImageId =
imgId(filePath)

proc loadImage*(id: ImageId; image: auto) =
discard
Loading