Skip to content
Merged
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
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changes

## 0.40.2

- Export producer-owned `RenderFragments`, fragment handles, cursors, and their
mutation/query API through the native dynamic-library facade. Render fragment
trees can now be rendered directly through `figdraw/windowing`.
- Add the `imageStyle(ImageId, Fill)` overload to the native facade and preserve
custom fills for both image IDs and image references.

## 0.39.0

- Expose `resetFontCache` and font/source/metadata lookups through the regular
Expand Down
4 changes: 2 additions & 2 deletions figdraw.nimble
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = "0.40.1"
version = "0.40.2"
author = "Jaremy Creechley"
description = "UI Engine for Nim"
license = "MIT"
Expand Down Expand Up @@ -45,7 +45,7 @@ feature "vulkan":
feature "metal":
requires "https://github.com/elcritch/metalx#head"
feature "sharedlib":
requires "gh:elcritch/binny >= 0.5.21"
requires "gh:elcritch/binny >= 0.5.22"

when defined(feature.figdraw.sharedlib):
import std/os
Expand Down
8 changes: 8 additions & 0 deletions src/figdraw/bindings/native_bindings.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import pkg/pixie as pixie

import figdraw/commons
import figdraw/common/fonttypes
import figdraw/fignodes
import figdraw/figrender
import figdraw/windowing/siwinshim
from figdraw/common/typefaces import nil
from figdraw/common/imgutils import nil
from figdraw/renderfragments import nil

type SiwinRenderer* = FigRenderer[SiwinRenderBackend]

Expand Down Expand Up @@ -126,6 +128,12 @@ proc nativeReplayImageMessages*(renderer: SiwinRenderer) =
imgutils.replayImageMessages(renderer.ctx.imageMessages)
figrender.processImageMessages(renderer)

proc nativeRenderCursorZLevel*(cursor: renderfragments.RenderCursor): ZLevel =
cursor.zlevel

proc nativeRenderCursorIndex*(cursor: renderfragments.RenderCursor): FigIdx =
cursor.index

proc nativeRetainAtlasResources*(
renderer: SiwinRenderer, fontIds: openArray[FontId], imageIds: openArray[ImageId]
) =
Expand Down
8 changes: 6 additions & 2 deletions src/figdraw/bindings/native_dynlib.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"includeProcs": [
{"source": "native_bindings.nim", "name": "*"},
{"source": "../renderfragments.nim", "name": "*"},
{"source": "$pkg/siwin/platforms/any/window.nim", "name": "closed"},
{"source": "$pkg/siwin/platforms/any/window.nim", "name": "opened"},
{"source": "$pkg/siwin/platforms/any/window.nim", "name": "close"},
Expand Down Expand Up @@ -267,15 +268,18 @@
{"name": "FillKind", "module": "figdraw/common/filltypes", "source": "../common/filltypes.nim"},
{"name": "FillGradientAxis", "module": "figdraw/common/filltypes", "source": "../common/filltypes.nim"},
{"name": "SystemTypefaceFile", "module": "figdraw/extras/systemfonttypes", "source": "../extras/systemfonttypes.nim"},
{"name": "SystemTypeface", "module": "figdraw/extras/systemfonttypes", "source": "../extras/systemfonttypes.nim"},
{"name": "SystemTypeface", "module": "figdraw/extras/systemfonttypes", "source": "../extras/systemfonttypes.nim"}
],
"opaqueTypes": [
{"name": "SiwinRenderer", "source": "native_bindings.nim"},
{"name": "SiwinRenderBackend", "source": "../windowing/siwinshim.nim"},
{"name": "SiwinPresentationTarget", "source": "../windowing/siwinshim.nim"},
{"name": "FontRef", "source": "native_bindings.nim"},
{"name": "NativeImageRef", "source": "native_bindings.nim"},
{"name": "ImageMessageSubscription", "source": "native_bindings.nim"}
{"name": "ImageMessageSubscription", "source": "native_bindings.nim"},
{"name": "RenderFragments", "source": "../renderfragments.nim"},
{"name": "RenderFragmentHandle", "source": "../renderfragments.nim"},
{"name": "RenderCursor", "source": "../renderfragments.nim"}
],
"requireMatches": true
}
17 changes: 15 additions & 2 deletions src/figdraw/dynlib.nim
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,21 @@ proc loadImage*[T](id: ImageId, image: T) {.inline.} =
proc replaceImage*[T](id: ImageId, image: T) {.inline.} =
figdraw_native_abi.replaceImage(id, image.toImage())

proc imageStyle*(image: ImageRef): ImageStyle =
ImageStyle(id: image.id, fill: fill(rgba(255, 255, 255, 255)))
proc imageStyle*(
id: ImageId, imageFill: Fill = fill(rgba(255, 255, 255, 255))
): ImageStyle =
ImageStyle(id: id, fill: imageFill)

proc imageStyle*(
image: ImageRef, imageFill: Fill = fill(rgba(255, 255, 255, 255))
): ImageStyle =
imageStyle(image.id, imageFill)

proc zlevel*(cursor: RenderCursor): ZLevel {.inline.} =
nativeRenderCursorZLevel(cursor)

proc index*(cursor: RenderCursor): FigIdx {.inline.} =
nativeRenderCursorIndex(cursor)

proc drawableDashedRoundedRectBorderOps*(
box: bumpy.Rect,
Expand Down
9 changes: 9 additions & 0 deletions src/figdraw/windowing/dynlib.nim
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ proc renderFrame*(
) =
figdraw_native_abi.renderFrame(renderer.native, renders, size, clearMain, clearColor)

proc renderFrame*(
renderer: FigRenderer[SiwinRenderBackend],
renders: var RenderFragments,
size: vmath.Vec2,
clearMain = true,
clearColor = whiteColor,
) =
figdraw_native_abi.renderFrame(renderer.native, renders, size, clearMain, clearColor)

proc siwinWindowTitle*(suffix = "Siwin RenderList"): string =
"figdraw: " & siwinBackendName() & " + " & suffix

Expand Down
23 changes: 21 additions & 2 deletions src/figdraw/windowing/siwinshim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import siwin/platforms
import ../commons
import ../fignodes
import ../figrender
import ../renderfragments

const UseSiwinOpenGL = not (UseMetalBackend or UseVulkanBackend)
const NeedSiwinOpenGLContext = UseSiwinOpenGL or UseOpenGlFallback
Expand Down Expand Up @@ -932,9 +933,9 @@ proc endFrame*(renderer: FigRenderer[SiwinRenderBackend]) =
else:
discard

proc renderFrame*(
proc renderFrameImpl[Input: RenderInput](
renderer: FigRenderer[SiwinRenderBackend],
nodes: var Renders,
nodes: var Input,
frameSize: Vec2,
clearMain = true,
clearColor: Color = whiteColor,
Expand Down Expand Up @@ -977,3 +978,21 @@ proc renderFrame*(
clearColor = clearColor,
allowOpenGlFallback = not renderer.backendState.dedicatedRender,
)

proc renderFrame*(
renderer: FigRenderer[SiwinRenderBackend],
nodes: var Renders,
frameSize: Vec2,
clearMain = true,
clearColor: Color = whiteColor,
) =
renderer.renderFrameImpl(nodes, frameSize, clearMain, clearColor)

proc renderFrame*(
renderer: FigRenderer[SiwinRenderBackend],
nodes: var RenderFragments,
frameSize: Vec2,
clearMain = true,
clearColor: Color = whiteColor,
) =
renderer.renderFrameImpl(nodes, frameSize, clearMain, clearColor)
74 changes: 74 additions & 0 deletions tests/tdynlib_renderfragments.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import std/unittest

when defined(useNativeDynlib):
import figdraw

suite "native dynlib render fragments":
when defined(useNativeDynlib):
test "keeps fragment state opaque and mutates it in the producer":
doAssert not compiles(default(RenderFragments).value)
doAssert not compiles(default(RenderFragmentHandle).value)
doAssert not compiles(default(RenderCursor).value)

let fragments = newRenderFragments()
let root = fragments.addRoot(
0.ZLevel, Fig(kind: nkRectangle, screenBox: rect(0, 0, 100, 100))
)

var contents = RenderList()
discard contents.addRoot(Fig(kind: nkRectangle, screenBox: rect(10, 10, 20, 20)))
let original = fragments.attachChildFragment(0.ZLevel, root, 0, move contents)

check fragments.isValid(original)
check fragments.handleStatus(original) == rfsValid
check original.fragmentId() != 0
check fragments.effectiveChildCount(0.ZLevel, root) == 1

let cursors = fragments.fragmentRoots(original)
check cursors.len == 1
check cursors[0].zlevel == 0.ZLevel
check cursors[0].index == 0.FigIdx
check cursors[0].fragmentHandle() == original
check fragments[cursors[0]].kind == nkRectangle
check fragments[0.ZLevel].nodes.len == 1

var
levels: seq[ZLevel]
roots: seq[RenderCursor]
for lvl in fragments.levels():
levels.add lvl
for cursor in fragments.roots(0.ZLevel):
roots.add cursor
check levels == @[0.ZLevel]
check roots.len == 1

var children: seq[RenderCursor]
for cursor in fragments.children(fragments.nodeCursor(0.ZLevel, root)):
children.add cursor
check children == cursors

var replacement = RenderList()
discard replacement.addRoot(Fig(kind: nkRectangle))
discard replacement.addRoot(Fig(kind: nkRectangle))
let updated = fragments.replaceFragment(original, move replacement)

check not fragments.isValid(original)
check fragments.isValid(updated)
check updated.fragmentId() == original.fragmentId()
check fragments.effectiveChildCount(0.ZLevel, root) == 2
check fragments.materialize().len(0.ZLevel) == 3

test "constructs image styles from ids and references":
let
id = imgId("native-image-style")
customFill = fill(rgba(12, 34, 56, 255))
fromId = imageStyle(id, customFill)
fromRef = imageStyle(imageRef(id), customFill)

check fromId.id == id
check fromId.fill.color == customFill.color
check fromRef.id == id
check fromRef.fill.color == customFill.color
else:
test "requires useNativeDynlib":
skip()
Loading