From e58ef20cf9c12e6a1e5c1ab4facd1dba840d5729 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 8 Sep 2023 19:44:03 -0400 Subject: WIP: Working on images. Can't set up during draw, need to refactor --- virtual-programs/images.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index ee3988ea..e9807b85 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -64,7 +64,7 @@ namespace eval ::image { image[i][j * 3 + 2] = data[(i * width + j) * 3 + 2]; } } - } + } else { exit(1); } struct jpeg_compress_struct compress; struct jpeg_error_mgr error; -- cgit v1.2.3 From b9e5187c1bbf267f0ec4fc899ce926cb2167247f Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 11 Sep 2023 17:41:43 -0400 Subject: WIP: Images starting to work --- virtual-programs/images.folk | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index e9807b85..8af24aee 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -160,6 +160,27 @@ namespace eval ::image { // TODO: Free the JPEG. // ckfree(im.data); } + $cc proc rechannel {image_t im int components} image_t { + if (im.components == components) return im; + if (components != 4 || im.components != 3) exit(2); + + image_t ret = im; + ret.components = components; + ret.bytesPerRow = ret.width * ret.components; + ret.data = folkHeapAlloc(ret.bytesPerRow * ret.height); + + for(int i = 0; i < ret.width*ret.height; i++) { + int r = im.data[i*im.components+0], + g = im.data[i*im.components+1], + b = im.data[i*im.components+2]; + + ret.data[i*ret.components+0] = r; + ret.data[i*ret.components+1] = g; + ret.data[i*ret.components+2] = b; + ret.data[i*ret.components+3] = 255; + } + return ret; + } $cc compile variable imagesCache [dict create] -- cgit v1.2.3 From f2ac1aa99d4842585355cafac600d5bddd6716f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Cuervo?= Date: Tue, 12 Sep 2023 11:15:54 -0400 Subject: Always cast swapChainBuffers and pushConstants, fix MacOS lib linking --- virtual-programs/images.folk | 3 +++ 1 file changed, 3 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index 8af24aee..18876944 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -27,6 +27,9 @@ namespace eval ::image { set cc [c create] c loadlib [expr {$tcl_platform(os) eq "Darwin" ? "/opt/homebrew/lib/libjpeg.dylib" : [lindex [exec /usr/sbin/ldconfig -p | grep libjpeg] end]}] + if {$tcl_platform(os) eq "Darwin"} { + $cc cflags -I/opt/homebrew/include -L/opt/homebrew/lib + } $cc cflags -ljpeg source "pi/cUtils.tcl" defineImageType $cc -- cgit v1.2.3 From 976f92f5faae252a6245b873800d56c44c8a2b05 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 15 Sep 2023 21:32:40 -0400 Subject: WIP: Stub in GPU into Folk. Doesn't draw yet --- virtual-programs/display.folk | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 674cf1f7..7d4f47b6 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -38,8 +38,25 @@ namespace eval ::Display { } On process { - source pi/Display.tcl - Display::init + source pi/Gpu.tcl + Gpu::init + + namespace eval Display { + proc start {} {} + + proc stroke {points width color} { + + } + proc circle {x y radius thickness color} {} + proc text {x y scale text radians} {} + proc fillTriangle {args} {} + proc fillQuad {args} {} + proc fillPolygon {args} {} + proc image {x y im radians {scale 1.0}} {} + + proc end {} {} + } + puts "Display tid: [getTid]" # TODO: Clean this up. We retract these so that we don't bounce @@ -77,11 +94,13 @@ On process { } set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] + set renderTime [baretime { + Display::start + foreach command $displayCommands { {*}$command } + Display::end + }] - set renderTime [baretime [list foreach command $displayCommands { {*}$command }]] - set commitTime [baretime commitThenClearStaging] - - Commit { Claim the display time is "render $renderTime us + commit $commitTime us ($::stepTime)" } + Commit { Claim the display time is "render $renderTime us ($::stepTime)" } Step } } -- cgit v1.2.3 From f7eb36e51fab7abd5ebc74dce9419d01e4a1dfa7 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 15 Sep 2023 21:36:42 -0400 Subject: display: Add basic stroke support --- virtual-programs/display.folk | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 7d4f47b6..c9c172cc 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -40,12 +40,29 @@ namespace eval ::Display { On process { source pi/Gpu.tcl Gpu::init + Gpu::ImageManager::imageManagerInit namespace eval Display { - proc start {} {} + variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { + float l = length(to - from); + vec2 d = (to - from) / l; + vec2 q = (gl_FragCoord.xy - (from + to)*0.5); + q = mat2(d.x, -d.y, d.y, d.x) * q; + q = abs(q) - vec2(l, thickness)*0.5; + float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0); + + return dist < 0.0 ? vec4(1, 0, 1, 1) : vec4(0, 0, 0, 0); + }] - proc stroke {points width color} { + proc start {} { Gpu::drawStart } + proc stroke {points width color} { + variable line + for {set i 0} {$i < [expr {[llength $points] - 1}]} {incr i} { + set from [lindex $points $i] + set to [lindex $points [expr $i+1]] + Gpu::draw $line $from $to $width + } } proc circle {x y radius thickness color} {} proc text {x y scale text radians} {} @@ -54,7 +71,7 @@ On process { proc fillPolygon {args} {} proc image {x y im radians {scale 1.0}} {} - proc end {} {} + proc end {} { Gpu::drawEnd } } puts "Display tid: [getTid]" -- cgit v1.2.3 From 6b7305d5adb099291c3a8866a899963bf3abd8c3 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sun, 17 Sep 2023 03:59:54 -0400 Subject: display: Add basic (wrong scale) text support, PT Sans --- virtual-programs/display.folk | 113 +++++++++++++++++++++++++++++++++++++++++- virtual-programs/images.folk | 4 +- 2 files changed, 113 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index c9c172cc..31dfdb2a 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -43,6 +43,98 @@ On process { Gpu::ImageManager::imageManagerInit namespace eval Display { + variable cross2d [Gpu::fn {vec2 a vec2 b} float { + return a.x*b.y - a.y*b.x; + }] + variable invBilinear [Gpu::fn {vec2 p vec2 a vec2 b vec2 c vec2 d} {cross2d} vec2 { + vec2 res = vec2(-1.0); + + vec2 e = b-a; + vec2 f = d-a; + vec2 g = a-b+c-d; + vec2 h = p-a; + + float k2 = cross2d( g, f ); + float k1 = cross2d( e, f ) + cross2d( h, g ); + float k0 = cross2d( h, e ); + + // if edges are parallel, this is a linear equation + if( abs(k2)<0.001 ) + { + res = vec2( (h.x*k1+f.x*k0)/(e.x*k1-g.x*k0), -k0/k1 ); + } + // otherwise, it's a quadratic + else + { + float w = k1*k1 - 4.0*k0*k2; + if( w<0.0 ) return vec2(-1.0); + w = sqrt( w ); + + float ik2 = 0.5/k2; + float v = (-k1 - w)*ik2; + float u = (h.x - f.x*v)/(e.x + g.x*v); + + if( u<0.0 || u>1.0 || v<0.0 || v>1.0 ) + { + v = (-k1 + w)*ik2; + u = (h.x - f.x*v)/(e.x + g.x*v); + } + res = vec2( u, v ); + } + return res; + }] + + namespace eval font { + proc load {name} { + set csvFd [open "vendor/fonts/$name.csv" r]; set csv [read $csvFd]; close $csvFd + set glyphInfos [dict create] + foreach line [split $csv "\n"] { + set info [lassign [split $line ,] glyph] + lassign $info advance \ + planeLeft planeBottom planeRight planeTop \ + atlasLeft atlasBottom atlasRight atlasTop + dict set glyphInfos $glyph \ + [list $advance \ + [list $planeLeft $planeBottom $planeRight $planeTop] \ + [list $atlasLeft $atlasBottom $atlasRight $atlasTop]] + } + + set im [image load "[pwd]/vendor/fonts/$name.png"] + set gim [Gpu::ImageManager::copyImageToGpu [image rechannel $im 4]] + + return [list $glyphInfos $im $gim] + } + proc glyphInfo {font char} { dict get [lindex $font 0] $char } + proc atlasImage {font} { lindex $font 1 } + proc gpuAtlasImage {font} { lindex $font 2 } + + namespace export * + namespace ensemble create + } + variable font [font load "PTSans-Regular"] + variable glyphMsd [Gpu::fn {sampler2D atlas vec4 atlasGlyphBounds vec2 glyphUv} vec4 { + vec2 atlasUv = mix(atlasGlyphBounds.xw, atlasGlyphBounds.zy, glyphUv); + return texture(atlas, vec2(atlasUv.x, 1.0-atlasUv.y)); + }] + variable median [Gpu::fn {float r float g float b} float { + return max(min(r, g), min(max(r, g), b)); + }] + variable glyph [Gpu::pipeline {sampler2D atlas vec2 atlasSize + vec4 atlasGlyphBounds + vec2 a vec2 b vec2 c vec2 d} \ + {invBilinear glyphMsd median} { + vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); + if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { + return vec4(0, 0, 0, 0); + } + + vec3 msd = glyphMsd(samplers[atlas], atlasGlyphBounds/atlasSize.xyxy, glyphUv).rgb; + float sd = median(msd.r, msd.g, msd.b); + float screenPxDistance = 4.5*(sd - 0.5); + float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); + return mix(vec4(0, 0, 0, 1), vec4(1, 1, 1, 1), opacity); + }] + variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { float l = length(to - from); vec2 d = (to - from) / l; @@ -65,7 +157,26 @@ On process { } } proc circle {x y radius thickness color} {} - proc text {x y scale text radians} {} + proc text {x0 y0 scale text radians} { + variable font + variable glyph + set fontAtlas [font gpuAtlasImage $font] + set fontAtlasSize [list [::image width [font atlasImage $font]] \ + [::image height [font atlasImage $font]]] + set x $x0; set y $y0 + for {set i 0} {$i < [string length $text]} {incr i} { + if {[string index $text $i] eq "\n"} { + set y [+ $y 100]; set x $x0; continue + } + try { + set glyphInfo [font glyphInfo $font [scan [string index $text $i] %c]] + Gpu::draw $glyph $fontAtlas $fontAtlasSize \ + [lindex $glyphInfo 2] \ + [list $x $y] [list [+ $x 100] $y] [list [+ $x 100] [+ $y 100]] [list $x [+ $y 100]] + set x [+ $x 100] + } on error e { puts stderr $e } + } + } proc fillTriangle {args} {} proc fillQuad {args} {} proc fillPolygon {args} {} diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index 6bfd9bb3..1d491eec 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -5,8 +5,6 @@ # Wish $this displays camera slice $slice # } -if {$::isLaptop} { return } - # Generic image class for sub-image manipulations namespace eval ::image { proc width {im} { dict get $im width } @@ -32,7 +30,7 @@ namespace eval ::image { $cc cflags -I/opt/homebrew/include -L/opt/homebrew/lib } - $cc cflags -ljpeg + $cc cflags -ljpeg -lpng source "pi/cUtils.tcl" defineImageType $cc $cc include -- cgit v1.2.3 From 4f6331641e3971370cac98c8fc8819d2270debe5 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sun, 17 Sep 2023 18:22:13 -0400 Subject: display: Start using planeBounds to position characters properly Make display work on laptop --- virtual-programs/display.folk | 66 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 34 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 31dfdb2a..1991650a 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -1,10 +1,12 @@ -if {$::isLaptop} return - namespace eval ::Display { variable WIDTH variable HEIGHT variable LAYER 0 - regexp {mode "(\d+)x(\d+)"} [exec fbset] -> WIDTH HEIGHT + if {$::isLaptop} { + set WIDTH 640; set HEIGHT 480 + } else { + regexp {mode "(\d+)x(\d+)"} [exec fbset] -> WIDTH HEIGHT + } proc drawOnTop {func args} { set ::Display::LAYER 1 @@ -12,28 +14,14 @@ namespace eval ::Display { set ::Display::LAYER 0 } - proc stroke {points width color} { - uplevel [list Wish display runs [list Display::stroke $points $width $color] on layer $::Display::LAYER] - } - - proc circle {x y radius thickness color} { - uplevel [list Wish display runs [list Display::circle $x $y $radius $thickness $color] on layer $::Display::LAYER] - } - - proc text args { - uplevel [list Wish display runs [list Display::text {*}$args] on layer $::Display::LAYER] - } - - proc fillTriangle args { - uplevel [list Wish display runs [list Display::fillTriangle {*}$args] on layer $::Display::LAYER] - } - - proc fillQuad args { - uplevel [list Wish display runs [list Display::fillQuad {*}$args] on layer $::Display::LAYER] - } - - proc fillPolygon args { - uplevel [list Wish display runs [list Display::fillPolygon {*}$args] on layer $::Display::LAYER] + # Create proxy versions of drawing primitives for the main Folk + # process (that will forward those draw commands to the display + # subprocess). + foreach func {stroke circle text fillTriangle fillQuad fillPolygon} { + proc $func args { + set func [lindex [info level 0] 0] + uplevel [list Wish display runs [list $func {*}$args] on layer $::Display::LAYER] + } } } @@ -163,17 +151,26 @@ On process { set fontAtlas [font gpuAtlasImage $font] set fontAtlasSize [list [::image width [font atlasImage $font]] \ [::image height [font atlasImage $font]]] + set em [* $scale 40.0] set x $x0; set y $y0 for {set i 0} {$i < [string length $text]} {incr i} { - if {[string index $text $i] eq "\n"} { - set y [+ $y 100]; set x $x0; continue + set char [string index $text $i] + if {$char eq "\n"} { + set y [+ $y $em]; set x $x0; continue } try { - set glyphInfo [font glyphInfo $font [scan [string index $text $i] %c]] - Gpu::draw $glyph $fontAtlas $fontAtlasSize \ - [lindex $glyphInfo 2] \ - [list $x $y] [list [+ $x 100] $y] [list [+ $x 100] [+ $y 100]] [list $x [+ $y 100]] - set x [+ $x 100] + set glyphInfo [font glyphInfo $font [scan $char %c]] + lassign $glyphInfo advance planeBounds atlasBounds + if {$char ne " "} { + lassign [lmap v $planeBounds {* $v $em}] left bottom right top + Gpu::draw $glyph $fontAtlas $fontAtlasSize \ + $atlasBounds \ + [list [+ $x $left] [- $y $top]] \ + [list [+ $x $right] [- $y $top]] \ + [list [+ $x $right] [+ $y $bottom]] \ + [list [+ $x $left] [+ $y $bottom]] + } + set x [+ $x [* $advance $em]] } on error e { puts stderr $e } } } @@ -182,10 +179,10 @@ On process { proc fillPolygon {args} {} proc image {x y im radians {scale 1.0}} {} - proc end {} { Gpu::drawEnd } + proc end {} { Gpu::drawEnd; Gpu::poll } } - puts "Display tid: [getTid]" + puts "Display pid: [pid]" # TODO: Clean this up. We retract these so that we don't bounce # statements back to the main Folk process that it sends us. @@ -224,6 +221,7 @@ On process { set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] set renderTime [baretime { Display::start + Display::text 100 100 1.0 "Hello, world!" 0 foreach command $displayCommands { {*}$command } Display::end }] -- cgit v1.2.3 From 317eac5efea896aa1f214f72ba81ce43f84bb58f Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 13:28:43 -0400 Subject: display: Fix text orientation, remove dupe code from Gpu --- virtual-programs/display.folk | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 1991650a..08d617c3 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -115,7 +115,6 @@ On process { if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { return vec4(0, 0, 0, 0); } - vec3 msd = glyphMsd(samplers[atlas], atlasGlyphBounds/atlasSize.xyxy, glyphUv).rgb; float sd = median(msd.r, msd.g, msd.b); float screenPxDistance = 4.5*(sd - 0.5); @@ -163,12 +162,14 @@ On process { lassign $glyphInfo advance planeBounds atlasBounds if {$char ne " "} { lassign [lmap v $planeBounds {* $v $em}] left bottom right top + set quad [list \ + [list [+ $x $left] [- $y $top]] \ + [list [+ $x $right] [- $y $top]] \ + [list [+ $x $right] [- $y $bottom]] \ + [list [+ $x $left] [- $y $bottom]]] + stroke $quad 10 red Gpu::draw $glyph $fontAtlas $fontAtlasSize \ - $atlasBounds \ - [list [+ $x $left] [- $y $top]] \ - [list [+ $x $right] [- $y $top]] \ - [list [+ $x $right] [+ $y $bottom]] \ - [list [+ $x $left] [+ $y $bottom]] + $atlasBounds {*}$quad } set x [+ $x [* $advance $em]] } on error e { puts stderr $e } @@ -221,7 +222,8 @@ On process { set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] set renderTime [baretime { Display::start - Display::text 100 100 1.0 "Hello, world!" 0 + Display::text 100 100 1.0 "Hello, pworld!" 0 + Display::stroke {{100 100} {400 100}} 4 red foreach command $displayCommands { {*}$command } Display::end }] -- cgit v1.2.3 From 80f3fc6efa21ddb8d8fc92bfaf6d6b9be1be66e6 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 13:31:34 -0400 Subject: display: debug cleanup --- virtual-programs/display.folk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 08d617c3..1a6246fe 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -167,7 +167,7 @@ On process { [list [+ $x $right] [- $y $top]] \ [list [+ $x $right] [- $y $bottom]] \ [list [+ $x $left] [- $y $bottom]]] - stroke $quad 10 red + # stroke $quad 10 red Gpu::draw $glyph $fontAtlas $fontAtlasSize \ $atlasBounds {*}$quad } @@ -223,7 +223,7 @@ On process { set renderTime [baretime { Display::start Display::text 100 100 1.0 "Hello, pworld!" 0 - Display::stroke {{100 100} {400 100}} 4 red + # Display::stroke {{100 100} {400 100}} 4 red foreach command $displayCommands { {*}$command } Display::end }] -- cgit v1.2.3 From 262234a1bbe30b48bfae3418162c104865a0a56a Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 15:53:56 -0400 Subject: Gpu: Pass quad into vertex shader as arg (Preparing for bounded drawing to speed things up.) Also derecommend not using `return`. --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 1a6246fe..b9dcfe84 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -168,7 +168,7 @@ On process { [list [+ $x $right] [- $y $bottom]] \ [list [+ $x $left] [- $y $bottom]]] # stroke $quad 10 red - Gpu::draw $glyph $fontAtlas $fontAtlasSize \ + Gpu::draw $glyph $quad $fontAtlas $fontAtlasSize \ $atlasBounds {*}$quad } set x [+ $x [* $advance $em]] -- cgit v1.2.3 From 8d96d1883fd2a476f2fa6aa0b7539166547aeaea Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 16:40:17 -0400 Subject: display: Add fullscreen vertex shaders to start --- virtual-programs/display.folk | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index b9dcfe84..a1aa9583 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -109,8 +109,10 @@ On process { }] variable glyph [Gpu::pipeline {sampler2D atlas vec2 atlasSize vec4 atlasGlyphBounds - vec2 a vec2 b vec2 c vec2 d} \ - {invBilinear glyphMsd median} { + vec2 a vec2 b vec2 c vec2 d} { + vec2 vertices[4] = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1)); + return vec4(vertices[gl_VertexIndex], 0.0, 1.0); + } {invBilinear glyphMsd median} { vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { return vec4(0, 0, 0, 0); @@ -123,6 +125,9 @@ On process { }] variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { + vec2 vertices[4] = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1)); + return vec4(vertices[gl_VertexIndex], 0.0, 1.0); + } { float l = length(to - from); vec2 d = (to - from) / l; vec2 q = (gl_FragCoord.xy - (from + to)*0.5); @@ -168,7 +173,7 @@ On process { [list [+ $x $right] [- $y $bottom]] \ [list [+ $x $left] [- $y $bottom]]] # stroke $quad 10 red - Gpu::draw $glyph $quad $fontAtlas $fontAtlasSize \ + Gpu::draw $glyph $fontAtlas $fontAtlasSize \ $atlasBounds {*}$quad } set x [+ $x [* $advance $em]] -- cgit v1.2.3 From 2cf8c2e68424d3deec758a417a490b4d13e6327f Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 18:49:36 -0400 Subject: display: WIP: Move to clipped drawing using vertex shaders Letters/lines are clipped a bit wrong rn. --- virtual-programs/display.folk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index a1aa9583..201c348e 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -110,8 +110,9 @@ On process { variable glyph [Gpu::pipeline {sampler2D atlas vec2 atlasSize vec4 atlasGlyphBounds vec2 a vec2 b vec2 c vec2 d} { - vec2 vertices[4] = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1)); - return vec4(vertices[gl_VertexIndex], 0.0, 1.0); + vec2 vertices[4] = vec2[4](a, b, c, d); + vec2 v = (2.0*vertices[gl_VertexIndex] - _resolution)/_resolution; + return vec4(v, 0.0, 1.0); } {invBilinear glyphMsd median} { vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { @@ -125,8 +126,9 @@ On process { }] variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { - vec2 vertices[4] = vec2[4](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1)); - return vec4(vertices[gl_VertexIndex], 0.0, 1.0); + vec2 vertices[4] = vec2[4](from - thickness, vec2(from.x - thickness, to.y + thickness), vec2(to.x + thickness, from.y - thickness), to + thickness); + vec2 v = (2.0*vertices[gl_VertexIndex] - _resolution)/_resolution; + return vec4(v, 0.0, 1.0); } { float l = length(to - from); vec2 d = (to - from) / l; -- cgit v1.2.3 From 1a234233662773204f85dfaad8cc99f13b16ad14 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 23:23:44 -0400 Subject: display: Text works on table! Use abdc draw order (because that's how to draw a quad w/ triangle strip topology) --- virtual-programs/display.folk | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 201c348e..6a703bce 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -110,7 +110,7 @@ On process { variable glyph [Gpu::pipeline {sampler2D atlas vec2 atlasSize vec4 atlasGlyphBounds vec2 a vec2 b vec2 c vec2 d} { - vec2 vertices[4] = vec2[4](a, b, c, d); + vec2 vertices[4] = vec2[4](a, b, d, c); vec2 v = (2.0*vertices[gl_VertexIndex] - _resolution)/_resolution; return vec4(v, 0.0, 1.0); } {invBilinear glyphMsd median} { @@ -122,7 +122,7 @@ On process { float sd = median(msd.r, msd.g, msd.b); float screenPxDistance = 4.5*(sd - 0.5); float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); - return mix(vec4(0, 0, 0, 1), vec4(1, 1, 1, 1), opacity); + return mix(vec4(0, 0, 0, 0), vec4(1, 1, 1, 1), opacity); }] variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { @@ -229,8 +229,6 @@ On process { set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] set renderTime [baretime { Display::start - Display::text 100 100 1.0 "Hello, pworld!" 0 - # Display::stroke {{100 100} {400 100}} 4 red foreach command $displayCommands { {*}$command } Display::end }] -- cgit v1.2.3 From 6fe7e9078e3f26a189781668449177a15c00c1cf Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 18 Sep 2023 23:52:14 -0400 Subject: Gpu: Vertex shader cleanup (do scaling to -1, 1 internally) --- virtual-programs/display.folk | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 6a703bce..ea8218c5 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -111,8 +111,7 @@ On process { vec4 atlasGlyphBounds vec2 a vec2 b vec2 c vec2 d} { vec2 vertices[4] = vec2[4](a, b, d, c); - vec2 v = (2.0*vertices[gl_VertexIndex] - _resolution)/_resolution; - return vec4(v, 0.0, 1.0); + return vertices[gl_VertexIndex]; } {invBilinear glyphMsd median} { vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { @@ -126,9 +125,13 @@ On process { }] variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { - vec2 vertices[4] = vec2[4](from - thickness, vec2(from.x - thickness, to.y + thickness), vec2(to.x + thickness, from.y - thickness), to + thickness); - vec2 v = (2.0*vertices[gl_VertexIndex] - _resolution)/_resolution; - return vec4(v, 0.0, 1.0); + vec2 vertices[4] = vec2[4]( + min(from, to) - thickness, + vec2(max(from.x, to.x) + thickness, min(from.y, to.y) - thickness), + vec2(min(from.y, to.y) - thickness, max(from.y, to.y) + thickness), + max(from, to) + thickness + ); + return vertices[gl_VertexIndex]; } { float l = length(to - from); vec2 d = (to - from) / l; -- cgit v1.2.3 From 8f65f6d3d91ed341fe0af016c6751335cb554333 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 19 Sep 2023 00:47:34 -0400 Subject: display: Text rotate works. Delete old code for lineclip/rotate --- virtual-programs/display.folk | 68 +++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 19 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index ea8218c5..f7c33ce3 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -92,7 +92,8 @@ On process { return [list $glyphInfos $im $gim] } - proc glyphInfo {font char} { dict get [lindex $font 0] $char } + proc hasGlyphInfo {font charCode} { dict exists [lindex $font 0] $charCode } + proc glyphInfo {font charCode} { dict get [lindex $font 0] $charCode } proc atlasImage {font} { lindex $font 1 } proc gpuAtlasImage {font} { lindex $font 2 } @@ -154,37 +155,66 @@ On process { } } proc circle {x y radius thickness color} {} + + proc textMetrics {text scale} { + set em [* $scale 30.0] + set x $x0; set y $y0 + for {set i 0} {$i < [string length $text]} {incr i} { + set char [string index $text $i] + if {$char eq "\n"} { + set y [+ $y $em]; set x $x0; continue + } + set charCode [scan $char %c] + if {[font hasGlyphInfo $font $charCode]} { + set glyphInfo [font glyphInfo $font $charCode] + } else { + set glyphInfo [font glyphInfo $font [scan ? %c]] + } + lassign $glyphInfo advance planeBounds atlasBounds + set x [+ $x [* $advance $em]] + } + return [list $x $y] + } proc text {x0 y0 scale text radians} { variable font variable glyph set fontAtlas [font gpuAtlasImage $font] set fontAtlasSize [list [::image width [font atlasImage $font]] \ [::image height [font atlasImage $font]]] - set em [* $scale 40.0] + set em [* $scale 30.0] set x $x0; set y $y0 + set lineNum 0 for {set i 0} {$i < [string length $text]} {incr i} { set char [string index $text $i] if {$char eq "\n"} { - set y [+ $y $em]; set x $x0; continue + incr lineNum + lassign [vec2 add [list $x0 $y0] \ + [vec2 rotate [list 0 [* $lineNum $em]] $radians]] x y + continue } - try { - set glyphInfo [font glyphInfo $font [scan $char %c]] - lassign $glyphInfo advance planeBounds atlasBounds - if {$char ne " "} { - lassign [lmap v $planeBounds {* $v $em}] left bottom right top - set quad [list \ - [list [+ $x $left] [- $y $top]] \ - [list [+ $x $right] [- $y $top]] \ - [list [+ $x $right] [- $y $bottom]] \ - [list [+ $x $left] [- $y $bottom]]] - # stroke $quad 10 red - Gpu::draw $glyph $fontAtlas $fontAtlasSize \ - $atlasBounds {*}$quad - } - set x [+ $x [* $advance $em]] - } on error e { puts stderr $e } + set charCode [scan $char %c] + if {[font hasGlyphInfo $font $charCode]} { + set glyphInfo [font glyphInfo $font $charCode] + } else { + set glyphInfo [font glyphInfo $font [scan ? %c]] + } + lassign $glyphInfo advance planeBounds atlasBounds + if {$char ne " "} { + lassign [lmap v $planeBounds {* $v $em}] left bottom right top + set quad [list \ + [vec2 add [list $x $y] [vec2 rotate [list $left [- $top]] $radians]] \ + [vec2 add [list $x $y] [vec2 rotate [list $right [- $top]] $radians]] \ + [vec2 add [list $x $y] [vec2 rotate [list $right [- $bottom]] $radians]] \ + [vec2 add [list $x $y] [vec2 rotate [list $left [- $bottom]] $radians]]] + # stroke $quad 10 red + Gpu::draw $glyph $fontAtlas $fontAtlasSize \ + $atlasBounds {*}$quad + } + lassign [vec2 add [list $x $y] \ + [vec2 rotate [list [* $advance $em] 0] $radians]] x y } } + proc fillTriangle {args} {} proc fillQuad {args} {} proc fillPolygon {args} {} -- cgit v1.2.3 From 370f2f88246233f721db7eb28416ec69e27f4ad2 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Wed, 20 Sep 2023 09:07:49 -0400 Subject: display: Fix textMetrics --- virtual-programs/display.folk | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index f7c33ce3..b0fe3ec1 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -26,6 +26,8 @@ namespace eval ::Display { } On process { + puts "Display pid: [pid]" + source pi/Gpu.tcl Gpu::init Gpu::ImageManager::imageManagerInit @@ -157,12 +159,13 @@ On process { proc circle {x y radius thickness color} {} proc textMetrics {text scale} { + variable font set em [* $scale 30.0] - set x $x0; set y $y0 + set x 0; set y 0 for {set i 0} {$i < [string length $text]} {incr i} { set char [string index $text $i] if {$char eq "\n"} { - set y [+ $y $em]; set x $x0; continue + set y [+ $y $em]; set x 0; continue } set charCode [scan $char %c] if {[font hasGlyphInfo $font $charCode]} { @@ -223,8 +226,6 @@ On process { proc end {} { Gpu::drawEnd; Gpu::poll } } - puts "Display pid: [pid]" - # TODO: Clean this up. We retract these so that we don't bounce # statements back to the main Folk process that it sends us. Retract /anyone/ wishes $::thisProcess shares all wishes -- cgit v1.2.3 From dca67964e03709237a888f97ff3481f5e1cd579c Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Wed, 20 Sep 2023 22:52:04 -0400 Subject: display: Fix line vertices --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index b0fe3ec1..dc0fb2ea 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -131,7 +131,7 @@ On process { vec2 vertices[4] = vec2[4]( min(from, to) - thickness, vec2(max(from.x, to.x) + thickness, min(from.y, to.y) - thickness), - vec2(min(from.y, to.y) - thickness, max(from.y, to.y) + thickness), + vec2(min(from.x, to.x) - thickness, max(from.y, to.y) + thickness), max(from, to) + thickness ); return vertices[gl_VertexIndex]; -- cgit v1.2.3 From 1bcb36bfd6cdd9eec57cc2750a8c6a6d54fa010c Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 25 Jul 2023 14:54:31 -0400 Subject: Refactor AprilTags to make an object --- virtual-programs/apriltags.folk | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/apriltags.folk b/virtual-programs/apriltags.folk index 8bdd415a..69fcf51c 100644 --- a/virtual-programs/apriltags.folk +++ b/virtual-programs/apriltags.folk @@ -1,9 +1,10 @@ if {$::isLaptop} return +set tagfamily "tagStandard52h13" + # Plain detector. Runs on entire camera frame. set mainDetectorProcess [On process { source pi/AprilTags.tcl - AprilTags::init # TODO: Clean this up. We retract these so that we don't bounce # statements back to the main Folk process that it sends us. @@ -18,9 +19,10 @@ set mainDetectorProcess [On process { Wish $::thisProcess shares statements like \ [list /someone/ claims $::thisProcess has pid /pid/] + set detector [AprilTags new $tagfamily] When the camera frame is /grayFrame/ at /timestamp/ { set aprilTime [time { - set tags [AprilTags::detect $grayFrame] + set tags [$detector detect $grayFrame] }] Claim $::thisProcess detects tags $tags at $timestamp in time $aprilTime } @@ -30,7 +32,6 @@ set mainDetectorProcess [On process { # old camera frame. On process { source pi/AprilTags.tcl - AprilTags::init # TODO: Clean this up. We retract these so that we don't bounce # statements back to the main Folk process that it sends us. @@ -65,6 +66,8 @@ On process { } } + set detector [AprilTags new $tagfamily] + When the camera frame is /grayFrame/ at /timestamp/ & \ /process/ detects tags /prevTags/ at /something/ in time /something/ { @@ -89,7 +92,7 @@ On process { set subimage [subimage $grayFrame $x $y [- $x1 $x] [- $y1 $y]] set aprilTime [+ $aprilTime [baretime { - foreach tag [AprilTags::detect $subimage] { + foreach tag [$detector detect $subimage] { dict with tag { set center [vec2 add $center [list $x $y]] set corners [lmap corner $corners {vec2 add $corner [list $x $y]}] -- cgit v1.2.3 From 47ef27ec1bf87941faa22d28ac272c94d6a3f781 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Fri, 22 Sep 2023 18:06:18 -0400 Subject: Make consistent with labelling --- virtual-programs/errors.folk | 4 ++-- virtual-programs/title.folk | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/errors.folk b/virtual-programs/errors.folk index 555b45bb..28028710 100644 --- a/virtual-programs/errors.folk +++ b/virtual-programs/errors.folk @@ -7,5 +7,5 @@ When /p/ has error /err/ with info /info/ { } } - Wish $p has title $err -} \ No newline at end of file + Wish $p is titled $err +} diff --git a/virtual-programs/title.folk b/virtual-programs/title.folk index e17d9d75..fccacc17 100644 --- a/virtual-programs/title.folk +++ b/virtual-programs/title.folk @@ -1,6 +1,6 @@ # Title/footnote wish fulfillment # for wishes of the form: -# "Wish $tag has title "This is a tag"" or "Wish $tag has footnote "This is a footnote"" +# "Wish $tag is titled "This is a tag"" or "Wish $tag is footnoted "This is a footnote"" When /thing/ has region /region/ { @@ -9,7 +9,7 @@ When /thing/ has region /region/ { set top [vec2 add [region top $region] [vec2 rotate [list 0 -12] $radians]] set bot [vec2 add [region bottom $region] [vec2 rotate [list 0 16] $radians]] - When the collected matches for [list /someone/ wishes $thing has title /text/] are /matches/ { + When the collected matches for [list /someone/ wishes $thing is titled /text/] are /matches/ { set text [join [lmap match $matches {dict get $match text}] "\n"] if {$text eq ""} { return } @@ -17,7 +17,7 @@ When /thing/ has region /region/ { Display::text {*}$top $scale $text $radians } - When the collected matches for [list /someone/ wishes $thing has footnote /text/] are /matches/ { + When the collected matches for [list /someone/ wishes $thing is footnoted /text/] are /matches/ { set text [join [lmap match $matches {dict get $match text}] "\n"] if {$text eq ""} { return } -- cgit v1.2.3 From d03e5a2ff6fb6dda4aa240e8d05f4ef95b6aaec4 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Fri, 22 Sep 2023 19:08:05 -0400 Subject: Add connections between objects with regions --- virtual-programs/connections.folk | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 virtual-programs/connections.folk (limited to 'virtual-programs') diff --git a/virtual-programs/connections.folk b/virtual-programs/connections.folk new file mode 100644 index 00000000..c66fba1d --- /dev/null +++ b/virtual-programs/connections.folk @@ -0,0 +1,56 @@ +# Connection wish fulfillment +# for wishes of the form: +# "Wish $tag is connected to $tag2" or "Wish $tag is dynamically connected to $tag2" + +When /anyone/ wishes /source/ is connected to /sink/ & \ + /source/ has region /source_region/ & \ + /sink/ has region /sink_region/ { + + if {$source == $sink} {return} + + set source [region centroid $source_region] + set sink [region centroid $sink_region] + + set direction [vec2 sub $sink $source] + + set c [vec2 scale [vec2 add $source $sink] 0.5] + set angle [expr {atan2(-[lindex $direction 1], [lindex $direction 0]) - 3.14159/2}] + + set color grey + Display::stroke [list $source $sink ] 2 $color + shape 3 $c 30 $angle $color true +} + +set speed 75 +set spacing 50 +set maxsize 25 + +When /anyone/ wishes /source/ is dynamically connected to /sink/ & \ + /source/ has region /source_region/ & \ + /sink/ has region /sink_region/ { + + if {$source == $sink} {return} + + set source [region centroid $source_region] + set sink [region centroid $sink_region] + + set direction [vec2 normalize [vec2 sub $sink $source]] + set distance [vec2 distance $sink $source] + set angle [expr {atan2(-[lindex $direction 1], [lindex $direction 0]) - 3.14159/2}] + + lassign [vec2 scale [vec2 add $source $sink] 0.5] cx cy + + Display::stroke [list $source $sink ] 1 white + + + When the clock time is /t/ { + set offset [expr {round($t*$speed) % $spacing}] + set count [expr {round($distance / $spacing)}] + + for {set p $offset} {$p < $distance} {incr p $spacing} { + set c [vec2 add $source [vec2 scale $direction $p]] + set s [expr {min($maxsize, 0.20*min($p, $distance - $p))}] + shape 3 $c $s $angle white true + } + } +} -- cgit v1.2.3 From cd63ce61470bf5c0a2a54f576dae3c3b68b4fb45 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 23 Sep 2023 05:41:38 -0400 Subject: Gpu/display: Unify fns and args; start on frag args Preparing to do more with vertex shaders (compute quads and pass to frag) to reduce CPU work and speed up Pi 4. --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index dc0fb2ea..211bfa0a 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -115,7 +115,7 @@ On process { vec2 a vec2 b vec2 c vec2 d} { vec2 vertices[4] = vec2[4](a, b, d, c); return vertices[gl_VertexIndex]; - } {invBilinear glyphMsd median} { + } {fn invBilinear fn glyphMsd fn median} { vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { return vec4(0, 0, 0, 0); -- cgit v1.2.3 From 11394db087397078f4ba2b87a1e9c2a9e35805e7 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 23 Sep 2023 06:22:05 -0400 Subject: Gpu/display: Move a lot of glyph logic into shader Make vertex fns work. Effect on Pi 4 performance is good (15fps) but not great. --- virtual-programs/display.folk | 44 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 211bfa0a..d508748a 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -33,6 +33,12 @@ On process { Gpu::ImageManager::imageManagerInit namespace eval Display { + variable rotate [Gpu::fn {vec2 v float a} vec2 { + float s = sin(a); + float c = cos(a); + mat2 m = mat2(c, s, -s, c); + return m * v; + }] variable cross2d [Gpu::fn {vec2 a vec2 b} float { return a.x*b.y - a.y*b.x; }] @@ -112,10 +118,30 @@ On process { }] variable glyph [Gpu::pipeline {sampler2D atlas vec2 atlasSize vec4 atlasGlyphBounds - vec2 a vec2 b vec2 c vec2 d} { + vec4 planeGlyphBounds + vec2 pos float radians float em + fn rotate} { + float left = planeGlyphBounds[0] * em; + float bottom = planeGlyphBounds[1] * em; + float right = planeGlyphBounds[2] * em; + float top = planeGlyphBounds[3] * em; + vec2 a = pos + rotate(vec2(left, -top), radians); + vec2 b = pos + rotate(vec2(right, -top), radians); + vec2 c = pos + rotate(vec2(right, -bottom), radians); + vec2 d = pos + rotate(vec2(left, -bottom), radians); + vec2 vertices[4] = vec2[4](a, b, d, c); return vertices[gl_VertexIndex]; - } {fn invBilinear fn glyphMsd fn median} { + } {fn rotate fn invBilinear fn glyphMsd fn median} { + float left = planeGlyphBounds[0] * em; + float bottom = planeGlyphBounds[1] * em; + float right = planeGlyphBounds[2] * em; + float top = planeGlyphBounds[3] * em; + vec2 a = pos + rotate(vec2(left, -top), radians); + vec2 b = pos + rotate(vec2(right, -top), radians); + vec2 c = pos + rotate(vec2(right, -bottom), radians); + vec2 d = pos + rotate(vec2(left, -bottom), radians); + vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { return vec4(0, 0, 0, 0); @@ -203,15 +229,15 @@ On process { } lassign $glyphInfo advance planeBounds atlasBounds if {$char ne " "} { - lassign [lmap v $planeBounds {* $v $em}] left bottom right top - set quad [list \ - [vec2 add [list $x $y] [vec2 rotate [list $left [- $top]] $radians]] \ - [vec2 add [list $x $y] [vec2 rotate [list $right [- $top]] $radians]] \ - [vec2 add [list $x $y] [vec2 rotate [list $right [- $bottom]] $radians]] \ - [vec2 add [list $x $y] [vec2 rotate [list $left [- $bottom]] $radians]]] + # lassign [lmap v $planeBounds {* $v $em}] left bottom right top + # set quad [list \ + # [vec2 add [list $x $y] [vec2 rotate [list $left [- $top]] $radians]] \ + # [vec2 add [list $x $y] [vec2 rotate [list $right [- $top]] $radians]] \ + # [vec2 add [list $x $y] [vec2 rotate [list $right [- $bottom]] $radians]] \ + # [vec2 add [list $x $y] [vec2 rotate [list $left [- $bottom]] $radians]]] # stroke $quad 10 red Gpu::draw $glyph $fontAtlas $fontAtlasSize \ - $atlasBounds {*}$quad + $atlasBounds $planeBounds [list $x $y] $radians $em } lassign [vec2 add [list $x $y] \ [vec2 rotate [list [* $advance $em] 0] $radians]] x y -- cgit v1.2.3 From ea152053ab9865991ef7b08cfbe67dc093210505 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 23 Sep 2023 06:30:22 -0400 Subject: display: Fix glyph angles --- virtual-programs/display.folk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index d508748a..67f12767 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -137,10 +137,10 @@ On process { float bottom = planeGlyphBounds[1] * em; float right = planeGlyphBounds[2] * em; float top = planeGlyphBounds[3] * em; - vec2 a = pos + rotate(vec2(left, -top), radians); - vec2 b = pos + rotate(vec2(right, -top), radians); - vec2 c = pos + rotate(vec2(right, -bottom), radians); - vec2 d = pos + rotate(vec2(left, -bottom), radians); + vec2 a = pos + rotate(vec2(left, -top), -radians); + vec2 b = pos + rotate(vec2(right, -top), -radians); + vec2 c = pos + rotate(vec2(right, -bottom), -radians); + vec2 d = pos + rotate(vec2(left, -bottom), -radians); vec2 glyphUv = invBilinear(gl_FragCoord.xy, a, b, c, d); if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { -- cgit v1.2.3 From 7e1e6278bf637c9e1295cb1297d99312f359acbd Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 23 Sep 2023 06:40:42 -0400 Subject: display: Fix more glyph angles --- virtual-programs/display.folk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 67f12767..3fc02d85 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -125,10 +125,10 @@ On process { float bottom = planeGlyphBounds[1] * em; float right = planeGlyphBounds[2] * em; float top = planeGlyphBounds[3] * em; - vec2 a = pos + rotate(vec2(left, -top), radians); - vec2 b = pos + rotate(vec2(right, -top), radians); - vec2 c = pos + rotate(vec2(right, -bottom), radians); - vec2 d = pos + rotate(vec2(left, -bottom), radians); + vec2 a = pos + rotate(vec2(left, -top), -radians); + vec2 b = pos + rotate(vec2(right, -top), -radians); + vec2 c = pos + rotate(vec2(right, -bottom), -radians); + vec2 d = pos + rotate(vec2(left, -bottom), -radians); vec2 vertices[4] = vec2[4](a, b, d, c); return vertices[gl_VertexIndex]; -- cgit v1.2.3 From b581e494b06da36825cd3b9618838bfe9e4d28b6 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Mon, 25 Sep 2023 21:17:54 -0400 Subject: Add filled circles --- virtual-programs/display.folk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 674cf1f7..b07ec644 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -16,8 +16,8 @@ namespace eval ::Display { uplevel [list Wish display runs [list Display::stroke $points $width $color] on layer $::Display::LAYER] } - proc circle {x y radius thickness color} { - uplevel [list Wish display runs [list Display::circle $x $y $radius $thickness $color] on layer $::Display::LAYER] + proc circle {x y radius thickness color {filled false}} { + uplevel [list Wish display runs [list Display::circle $x $y $radius $thickness $color $filled] on layer $::Display::LAYER] } proc text args { -- cgit v1.2.3 From d01e2422a574842cc086b8167c5240eb9f500f74 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Mon, 25 Sep 2023 23:25:58 -0400 Subject: Send a list of commands to display --- virtual-programs/display.folk | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index b07ec644..b1610742 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -54,6 +54,8 @@ On process { [list /someone/ wishes display runs /command/ on layer /layer/] Wish $::thisProcess receives statements like \ [list /someone/ wishes display runs /command/] + Wish $::thisProcess receives statements like \ + [list /someone/ wishes display runs list /commands/] Wish $::thisProcess shares statements like \ [list /someone/ claims the display time is /displayTime/] @@ -65,6 +67,11 @@ On process { foreach match [Statements::findMatches {/someone/ wishes display runs /command/}] { lappend displayList [list 0 [dict get $match command]] } + foreach match [Statements::findMatches {/someone/ wishes display runs list /commands/}] { + foreach command [dict get $match commands] { + lappend displayList [list 0 $command] + } + } proc lcomp {a b} { set layerA [lindex $a 0] -- cgit v1.2.3 From e065cc16657118014dcf43d9f49146e9cc99f534 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 16:16:19 -0400 Subject: display: Revert display list stuff for now --- virtual-programs/display.folk | 7 ------- 1 file changed, 7 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index b1610742..b07ec644 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -54,8 +54,6 @@ On process { [list /someone/ wishes display runs /command/ on layer /layer/] Wish $::thisProcess receives statements like \ [list /someone/ wishes display runs /command/] - Wish $::thisProcess receives statements like \ - [list /someone/ wishes display runs list /commands/] Wish $::thisProcess shares statements like \ [list /someone/ claims the display time is /displayTime/] @@ -67,11 +65,6 @@ On process { foreach match [Statements::findMatches {/someone/ wishes display runs /command/}] { lappend displayList [list 0 [dict get $match command]] } - foreach match [Statements::findMatches {/someone/ wishes display runs list /commands/}] { - foreach command [dict get $match commands] { - lappend displayList [list 0 $command] - } - } proc lcomp {a b} { set layerA [lindex $a 0] -- cgit v1.2.3 From ef73ec928b677f6c9ff3024cc09a926b48438964 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 19:07:27 -0400 Subject: display: Reintroduce stroke color support --- virtual-programs/display.folk | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 3fc02d85..cc31575d 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -33,6 +33,8 @@ On process { Gpu::ImageManager::imageManagerInit namespace eval Display { + namespace eval Colors { source "pi/Colors.tcl" } + variable rotate [Gpu::fn {vec2 v float a} vec2 { float s = sin(a); float c = cos(a); @@ -153,7 +155,7 @@ On process { return mix(vec4(0, 0, 0, 0), vec4(1, 1, 1, 1), opacity); }] - variable line [Gpu::pipeline {vec2 from vec2 to float thickness} { + variable line [Gpu::pipeline {vec2 from vec2 to float thickness vec4 color} { vec2 vertices[4] = vec2[4]( min(from, to) - thickness, vec2(max(from.x, to.x) + thickness, min(from.y, to.y) - thickness), @@ -169,17 +171,22 @@ On process { q = abs(q) - vec2(l, thickness)*0.5; float dist = length(max(q, 0.0)) + min(max(q.x, q.y), 0.0); - return dist < 0.0 ? vec4(1, 0, 1, 1) : vec4(0, 0, 0, 0); + return dist < 0.0 ? color : vec4(0, 0, 0, 0); }] proc start {} { Gpu::drawStart } + proc getColor {color} { + if {[info exists Colors::$color]} { return [set Colors::$color] } \ + else { return $Colors::white } + } + proc stroke {points width color} { variable line for {set i 0} {$i < [expr {[llength $points] - 1}]} {incr i} { set from [lindex $points $i] set to [lindex $points [expr $i+1]] - Gpu::draw $line $from $to $width + Gpu::draw $line $from $to $width [getColor $color] } } proc circle {x y radius thickness color} {} -- cgit v1.2.3 From 731327e25249e75a442bef07696ec1f3a105c726 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 19:43:42 -0400 Subject: display: Add circle support. --- virtual-programs/display.folk | 46 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index cc31575d..fd30779b 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -155,6 +155,13 @@ On process { return mix(vec4(0, 0, 0, 0), vec4(1, 1, 1, 1), opacity); }] + proc start {} { Gpu::drawStart } + + proc getColor {color} { + if {[info exists Colors::$color]} { return [set Colors::$color] } \ + else { return $Colors::white } + } + variable line [Gpu::pipeline {vec2 from vec2 to float thickness vec4 color} { vec2 vertices[4] = vec2[4]( min(from, to) - thickness, @@ -173,14 +180,6 @@ On process { return dist < 0.0 ? color : vec4(0, 0, 0, 0); }] - - proc start {} { Gpu::drawStart } - - proc getColor {color} { - if {[info exists Colors::$color]} { return [set Colors::$color] } \ - else { return $Colors::white } - } - proc stroke {points width color} { variable line for {set i 0} {$i < [expr {[llength $points] - 1}]} {incr i} { @@ -189,7 +188,29 @@ On process { Gpu::draw $line $from $to $width [getColor $color] } } - proc circle {x y radius thickness color} {} + + # TODO: Fix bool support. + variable circle [Gpu::pipeline {vec2 center float radius float thickness vec4 color int filled} { + float r = radius + thickness; + vec2 vertices[4] = vec2[4]( + center - r, + vec2(center.x + r, center.y - r), + vec2(center.x - r, center.y + r), + center + r + ); + return vertices[gl_VertexIndex]; + } { + float dist = length(gl_FragCoord.xy - center) - radius; + if (filled == 1) { + return (dist < thickness) ? color : vec4(0, 0, 0, 0); + } else { + return (dist < thickness && dist > 0.0) ? color : vec4(0, 0, 0, 0); + } + }] + proc circle {x y radius thickness color {filled false}} { + variable circle + Gpu::draw $circle [list $x $y] $radius $thickness [getColor $color] [ne $filled "false"] + } proc textMetrics {text scale} { variable font @@ -236,13 +257,6 @@ On process { } lassign $glyphInfo advance planeBounds atlasBounds if {$char ne " "} { - # lassign [lmap v $planeBounds {* $v $em}] left bottom right top - # set quad [list \ - # [vec2 add [list $x $y] [vec2 rotate [list $left [- $top]] $radians]] \ - # [vec2 add [list $x $y] [vec2 rotate [list $right [- $top]] $radians]] \ - # [vec2 add [list $x $y] [vec2 rotate [list $right [- $bottom]] $radians]] \ - # [vec2 add [list $x $y] [vec2 rotate [list $left [- $bottom]] $radians]]] - # stroke $quad 10 red Gpu::draw $glyph $fontAtlas $fontAtlasSize \ $atlasBounds $planeBounds [list $x $y] $radians $em } -- cgit v1.2.3 From c1bac3003b74702eef36ecb123bb5cdd59d44657 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 20:13:48 -0400 Subject: display: Implement fillTriangle; fillPolygon also seems to work. --- virtual-programs/display.folk | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index fd30779b..fe0d883f 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -265,9 +265,42 @@ On process { } } - proc fillTriangle {args} {} - proc fillQuad {args} {} - proc fillPolygon {args} {} + variable fillTriangle [Gpu::pipeline {vec2 p0 vec2 p1 vec2 p2 vec4 color} { + vec2 vertices[4] = vec2[4](p0, p1, p2, p2); + return vertices[gl_VertexIndex]; + } { + return color; + }] + proc fillTriangle {p0 p1 p2 color} { + variable fillTriangle + Gpu::draw $fillTriangle $p0 $p1 $p2 [getColor $color] + } + + proc fillQuad {p0 p1 p2 p3 color} { + fillTriangle $p1 $p2 $p3 $color + fillTriangle $p0 $p1 $p3 $color + } + + proc fillPolygon {points color} { + set num_points [llength $points] + if {$num_points < 3} { + error "At least 3 points are required to form a polygon." + } elseif {$num_points == 3} { + eval fillTriangle $points $color + } elseif {$num_points == 4} { + eval fillQuad $points $color + } else { + # Get the first point in the list as the "base" point of the triangles + set p0 [lindex $points 0] + + for {set i 1} {$i < $num_points - 1} {incr i} { + set p1 [lindex $points $i] + set p2 [lindex $points [expr {$i+1}]] + fillTriangle $p0 $p1 $p2 $color + } + } + } + proc image {x y im radians {scale 1.0}} {} proc end {} { Gpu::drawEnd; Gpu::poll } -- cgit v1.2.3 From 482ae8f37976e4035845d2f596a0ec0af04827d7 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 20:15:57 -0400 Subject: display: This seems to fix fillQuad --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index fe0d883f..30b9e408 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -266,7 +266,7 @@ On process { } variable fillTriangle [Gpu::pipeline {vec2 p0 vec2 p1 vec2 p2 vec4 color} { - vec2 vertices[4] = vec2[4](p0, p1, p2, p2); + vec2 vertices[4] = vec2[4](p0, p1, p2, p0); return vertices[gl_VertexIndex]; } { return color; -- cgit v1.2.3 From 74fa2828cb7bee6a29931dcedcb9a06b2688d243 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 20:48:49 -0400 Subject: display: Basic image support (no rotation/scale yet + cache is hack) Fix various stride bugs with iamge copying/rechanneling. --- virtual-programs/display.folk | 34 +++++++++++++++++++++++++++++++++- virtual-programs/images.folk | 26 ++++++++++++++++---------- 2 files changed, 49 insertions(+), 11 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 30b9e408..ef24c9d8 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -301,7 +301,39 @@ On process { } } - proc image {x y im radians {scale 1.0}} {} + variable image [Gpu::pipeline {sampler2D image vec2 imageSize + vec2 pos float radians float scale} { + vec2 a = pos - imageSize/2; + vec2 b = pos + vec2(imageSize.x, -imageSize.y)/2; + vec2 c = pos + imageSize/2; + vec2 d = pos + vec2(-imageSize.x, imageSize.y)/2; + vec2 vertices[4] = vec2[4](a, b, d, c); + return vertices[gl_VertexIndex]; + } {fn invBilinear} { + vec2 a = pos - imageSize/2; + vec2 b = pos + vec2(imageSize.x, -imageSize.y)/2; + vec2 c = pos + imageSize/2; + vec2 d = pos + vec2(-imageSize.x, imageSize.y)/2; + vec2 p = gl_FragCoord.xy; + vec2 uv = invBilinear(p, a, b, c, d); + if( max( abs(uv.x-0.5), abs(uv.y-0.5))<0.5 ) { + return texture(samplers[image], uv); + } + return vec4(0.0, 0.0, 0.0, 0.0); + }] + variable imCache [dict create] + proc image {x y im radians {scale 1.0}} { + variable image + variable imCache + if {![dict exists $imCache $im]} { + set gim [Gpu::ImageManager::copyImageToGpu [::image rechannel $im 4]] + dict set imCache $im $gim + } + set gim [dict get $imCache $im] + puts $gim + Gpu::draw $image $gim [list [::image width $im] [::image height $im]] \ + [list $x $y] $radians $scale + } proc end {} { Gpu::drawEnd; Gpu::poll } } diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index 1d491eec..120b340a 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -262,6 +262,8 @@ namespace eval ::image { // TODO: Free the PNG. } + # Allocates(!) a copy of `im` with `components` channels. Up to + # the caller to free it. $cc proc rechannel {image_t im int components} image_t { if (im.components == components) return im; if (components != 4 || im.components != 3) exit(2); @@ -270,16 +272,20 @@ namespace eval ::image { ret.components = components; ret.bytesPerRow = ret.width * ret.components; ret.data = folkHeapAlloc(ret.bytesPerRow * ret.height); - - for(int i = 0; i < ret.width*ret.height; i++) { - int r = im.data[i*im.components+0], - g = im.data[i*im.components+1], - b = im.data[i*im.components+2]; - - ret.data[i*ret.components+0] = r; - ret.data[i*ret.components+1] = g; - ret.data[i*ret.components+2] = b; - ret.data[i*ret.components+3] = 255; + + for (int y = 0; y < im.height; y++) { + for (int x = 0; x < im.width; x++) { + int imidx = y*im.bytesPerRow + x*im.components; + int r = im.data[imidx+0], + g = im.data[imidx+1], + b = im.data[imidx+2]; + + int ridx = y*ret.bytesPerRow + x*ret.components; + ret.data[ridx+0] = r; + ret.data[ridx+1] = g; + ret.data[ridx+2] = b; + ret.data[ridx+3] = 255; + } } return ret; } -- cgit v1.2.3 From 254f53f31d45232428f703324a518a9bb48fad67 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Tue, 26 Sep 2023 21:14:22 -0400 Subject: display: Image rotation works. Also fix text rotation issues? Use fix from shadertoy comment to remove invBilinear instability on rotation. --- virtual-programs/display.folk | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index ef24c9d8..369e962a 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -44,6 +44,7 @@ On process { variable cross2d [Gpu::fn {vec2 a vec2 b} float { return a.x*b.y - a.y*b.x; }] + # See https://www.shadertoy.com/view/lsBSDm variable invBilinear [Gpu::fn {vec2 p vec2 a vec2 b vec2 c vec2 d} {cross2d} vec2 { vec2 res = vec2(-1.0); @@ -57,7 +58,8 @@ On process { float k0 = cross2d( h, e ); // if edges are parallel, this is a linear equation - if( abs(k2)<0.001 ) + k2 /= k0; k1 /= k0; k0 = 1.0; + if( abs(k2)<0.001*abs(k0) ) { res = vec2( (h.x*k1+f.x*k0)/(e.x*k1-g.x*k0), -k0/k1 ); } @@ -302,18 +304,19 @@ On process { } variable image [Gpu::pipeline {sampler2D image vec2 imageSize - vec2 pos float radians float scale} { - vec2 a = pos - imageSize/2; - vec2 b = pos + vec2(imageSize.x, -imageSize.y)/2; - vec2 c = pos + imageSize/2; - vec2 d = pos + vec2(-imageSize.x, imageSize.y)/2; + vec2 pos float radians float scale + fn rotate} { + vec2 a = pos + rotate(-imageSize/2, -radians); + vec2 b = pos + rotate(vec2(imageSize.x, -imageSize.y)/2, -radians); + vec2 c = pos + rotate(imageSize/2, -radians); + vec2 d = pos + rotate(vec2(-imageSize.x, imageSize.y)/2, -radians); vec2 vertices[4] = vec2[4](a, b, d, c); return vertices[gl_VertexIndex]; - } {fn invBilinear} { - vec2 a = pos - imageSize/2; - vec2 b = pos + vec2(imageSize.x, -imageSize.y)/2; - vec2 c = pos + imageSize/2; - vec2 d = pos + vec2(-imageSize.x, imageSize.y)/2; + } {fn invBilinear fn rotate} { + vec2 a = pos + rotate(-imageSize/2, -radians); + vec2 b = pos + rotate(vec2(imageSize.x, -imageSize.y)/2, -radians); + vec2 c = pos + rotate(imageSize/2, -radians); + vec2 d = pos + rotate(vec2(-imageSize.x, imageSize.y)/2, -radians); vec2 p = gl_FragCoord.xy; vec2 uv = invBilinear(p, a, b, c, d); if( max( abs(uv.x-0.5), abs(uv.y-0.5))<0.5 ) { @@ -323,6 +326,8 @@ On process { }] variable imCache [dict create] proc image {x y im radians {scale 1.0}} { + # TODO: Implement scale. + # TODO: Free images from cache. variable image variable imCache if {![dict exists $imCache $im]} { @@ -330,7 +335,6 @@ On process { dict set imCache $im $gim } set gim [dict get $imCache $im] - puts $gim Gpu::draw $image $gim [list [::image width $im] [::image height $im]] \ [list $x $y] $radians $scale } -- cgit v1.2.3 From 2f44373e4e04ce0b726948acc715ff925b061254 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 15:02:52 -0400 Subject: Gpu: Clean up sampler2D accesses. Clean up dep fns for fns. No more arbitrary samplers array -- you can just use the argname directly as a parameter to texture(). --- virtual-programs/display.folk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 369e962a..adc1ec04 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -45,7 +45,7 @@ On process { return a.x*b.y - a.y*b.x; }] # See https://www.shadertoy.com/view/lsBSDm - variable invBilinear [Gpu::fn {vec2 p vec2 a vec2 b vec2 c vec2 d} {cross2d} vec2 { + variable invBilinear [Gpu::fn {vec2 p vec2 a vec2 b vec2 c vec2 d fn cross2d} vec2 { vec2 res = vec2(-1.0); vec2 e = b-a; @@ -115,7 +115,7 @@ On process { variable font [font load "PTSans-Regular"] variable glyphMsd [Gpu::fn {sampler2D atlas vec4 atlasGlyphBounds vec2 glyphUv} vec4 { vec2 atlasUv = mix(atlasGlyphBounds.xw, atlasGlyphBounds.zy, glyphUv); - return texture(atlas, vec2(atlasUv.x, 1.0-atlasUv.y)); + return texture(atlas, vec2(atlasUv.x, 1.0-atlasUv.y)); }] variable median [Gpu::fn {float r float g float b} float { return max(min(r, g), min(max(r, g), b)); @@ -150,7 +150,7 @@ On process { if( max( abs(glyphUv.x-0.5), abs(glyphUv.y-0.5))>=0.5 ) { return vec4(0, 0, 0, 0); } - vec3 msd = glyphMsd(samplers[atlas], atlasGlyphBounds/atlasSize.xyxy, glyphUv).rgb; + vec3 msd = glyphMsd(atlas, atlasGlyphBounds/atlasSize.xyxy, glyphUv).rgb; float sd = median(msd.r, msd.g, msd.b); float screenPxDistance = 4.5*(sd - 0.5); float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); @@ -320,7 +320,7 @@ On process { vec2 p = gl_FragCoord.xy; vec2 uv = invBilinear(p, a, b, c, d); if( max( abs(uv.x-0.5), abs(uv.y-0.5))<0.5 ) { - return texture(samplers[image], uv); + return texture(image, uv); } return vec4(0.0, 0.0, 0.0, 0.0); }] -- cgit v1.2.3 From 471b7beb6e9ed19c6b432405528ffc781655bb6e Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 15:24:09 -0400 Subject: Gpu: Convert 1 & 3-channel images at callee. Start fixing cam slice. Removes rechannel! --- virtual-programs/display.folk | 4 ++-- virtual-programs/images.folk | 28 ---------------------------- 2 files changed, 2 insertions(+), 30 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index adc1ec04..4d4a1e09 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -100,7 +100,7 @@ On process { } set im [image load "[pwd]/vendor/fonts/$name.png"] - set gim [Gpu::ImageManager::copyImageToGpu [image rechannel $im 4]] + set gim [Gpu::ImageManager::copyImageToGpu $im] return [list $glyphInfos $im $gim] } @@ -331,7 +331,7 @@ On process { variable image variable imCache if {![dict exists $imCache $im]} { - set gim [Gpu::ImageManager::copyImageToGpu [::image rechannel $im 4]] + set gim [Gpu::ImageManager::copyImageToGpu $im] dict set imCache $im $gim } set gim [dict get $imCache $im] diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index 120b340a..ae793bc8 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -262,34 +262,6 @@ namespace eval ::image { // TODO: Free the PNG. } - # Allocates(!) a copy of `im` with `components` channels. Up to - # the caller to free it. - $cc proc rechannel {image_t im int components} image_t { - if (im.components == components) return im; - if (components != 4 || im.components != 3) exit(2); - - image_t ret = im; - ret.components = components; - ret.bytesPerRow = ret.width * ret.components; - ret.data = folkHeapAlloc(ret.bytesPerRow * ret.height); - - for (int y = 0; y < im.height; y++) { - for (int x = 0; x < im.width; x++) { - int imidx = y*im.bytesPerRow + x*im.components; - int r = im.data[imidx+0], - g = im.data[imidx+1], - b = im.data[imidx+2]; - - int ridx = y*ret.bytesPerRow + x*ret.components; - ret.data[ridx+0] = r; - ret.data[ridx+1] = g; - ret.data[ridx+2] = b; - ret.data[ridx+3] = 255; - } - } - return ret; - } - $cc compile variable imagesCache [dict create] -- cgit v1.2.3 From 038cf3b20327c1a983d5b29340704838b88d93c6 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 15:36:16 -0400 Subject: display: Center text again, shrink it a bit --- virtual-programs/display.folk | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 4d4a1e09..0bb0b88e 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -214,9 +214,9 @@ On process { Gpu::draw $circle [list $x $y] $radius $thickness [getColor $color] [ne $filled "false"] } - proc textMetrics {text scale} { + proc textExtent {text scale} { variable font - set em [* $scale 30.0] + set em [* $scale 25.0] set x 0; set y 0 for {set i 0} {$i < [string length $text]} {incr i} { set char [string index $text $i] @@ -240,8 +240,17 @@ On process { set fontAtlas [font gpuAtlasImage $font] set fontAtlasSize [list [::image width [font atlasImage $font]] \ [::image height [font atlasImage $font]]] - set em [* $scale 30.0] + + set extent [vec2 rotate [textExtent $text $scale] $radians] + + set em [* $scale 25.0] + + # TODO: Add text alignment/anchor options (right now, this + # setup centers the text). + set x0 [expr {$x0 - [lindex $extent 0]/2}] + set y0 [expr {$y0 - [lindex $extent 1]/2}] set x $x0; set y $y0 + set lineNum 0 for {set i 0} {$i < [string length $text]} {incr i} { set char [string index $text $i] -- cgit v1.2.3 From 66ffc532b2b7f476ee1e3e6a76aaf66f30194ee1 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 17:05:34 -0400 Subject: calibrate: WIP: Port to Vulkan. It kind of works but is unreliable (might just be general calibration problems, though). --- virtual-programs/images.folk | 6 +++++- virtual-programs/tags-and-calibration.folk | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index ae793bc8..5523e0a0 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -35,7 +35,11 @@ namespace eval ::image { defineImageType $cc $cc include $cc include - $cc import ::Heap::cc folkHeapAlloc as folkHeapAlloc + if {[namespace exists ::Heap]} { + $cc import ::Heap::cc folkHeapAlloc as folkHeapAlloc + } else { + $cc code { #define folkHeapAlloc malloc } + } $cc code { #undef EXTERN diff --git a/virtual-programs/tags-and-calibration.folk b/virtual-programs/tags-and-calibration.folk index b219b541..8bfa067c 100644 --- a/virtual-programs/tags-and-calibration.folk +++ b/virtual-programs/tags-and-calibration.folk @@ -33,6 +33,10 @@ When camera /camera/ has width /cameraWidth/ height /cameraHeight/ { [expr {double($dy)/$generatedCalibration::displayHeight*$Display::HEIGHT}]] } } + if {[llength $points] < 4} { + puts stderr "tags-and-calibration: Calibration isn't valid (not enough points). Stopping Folk." + exit 1 + } for {set i 0} {$i < [llength $points]} {incr i} { lassign [lindex $points $i] x$i y$i u$i v$i } -- cgit v1.2.3 From 75403d327b82d10e62e3c32a47b98cc23ea095c8 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 17:44:20 -0400 Subject: display: Load images before starting Gpu frame --- virtual-programs/display.folk | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 0bb0b88e..268e462d 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -334,15 +334,18 @@ On process { return vec4(0.0, 0.0, 0.0, 0.0); }] variable imCache [dict create] - proc image {x y im radians {scale 1.0}} { - # TODO: Implement scale. - # TODO: Free images from cache. - variable image + proc checkImCacheAndCopyIfNeeded {im} { variable imCache if {![dict exists $imCache $im]} { set gim [Gpu::ImageManager::copyImageToGpu $im] dict set imCache $im $gim } + } + proc image {x y im radians {scale 1.0}} { + # TODO: Implement scale. + # TODO: Free images from cache. + variable image + variable imCache set gim [dict get $imCache $im] Gpu::draw $image $gim [list [::image width $im] [::image height $im]] \ [list $x $y] $radians $scale @@ -386,6 +389,12 @@ On process { } set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] + foreach command $displayCommands { + if {[lindex $command 0] eq "Display::image"} { + set im [lindex $command 3] + Display::checkImCacheAndCopyIfNeeded $im + } + } set renderTime [baretime { Display::start foreach command $displayCommands { {*}$command } -- cgit v1.2.3 From e27ada832c5249724674500b44d21616c0c2407f Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 28 Sep 2023 20:51:54 -0400 Subject: main,camera: Can now free things from Folk interprocess heap Finish switch to dlmalloc. Get rid of hacky mempool in camera and just use the heap. --- virtual-programs/camera.folk | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/camera.folk b/virtual-programs/camera.folk index 428c4195..8f49393d 100644 --- a/virtual-programs/camera.folk +++ b/virtual-programs/camera.folk @@ -16,15 +16,37 @@ set height $::Camera::HEIGHT On process { source pi/Camera.tcl - Camera::init $width $height - puts "Camera tid: [getTid] booting at [clock milliseconds]" + set camera [Camera::cameraOpen "/dev/video0" $width $height] + Camera::cameraInit $camera + Camera::cameraStart $camera + # skip 5 frames for booting a cam + for {set i 0} {$i < 5} {incr i} { + Camera::cameraFrame $camera + } + + puts "Camera tid: [getTid] booted at [clock milliseconds]" + + fn grayFrame {} { + if {![Camera::cameraFrame $camera]} { + error "Failed to capture from camera" + } + set image [Camera::newImage $width $height 1] + Camera::cameraDecompressGray $camera $image + return $image + } + set ::oldFrames [list] When $::thisProcess has step count /c/ { - set grayFrame [Camera::grayFrame] + set frame [grayFrame] Commit { Claim the camera time is $::stepTime - Claim the camera frame is $grayFrame at [clock milliseconds] + Claim the camera frame is $frame at [clock milliseconds] + } + lappend ::oldFrames $frame + if {[llength $::oldFrames] >= 10} { + set ::oldFrames [lassign $::oldFrames oldestFrame] + Camera::freeImage $oldestFrame } } } -- cgit v1.2.3 From 0dbceb76d14382a0eab62f4c6c3bb5eb7e4d06eb Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 29 Sep 2023 07:02:06 -0400 Subject: display: Fix text extent computation / centering --- virtual-programs/display.folk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 268e462d..e42ea621 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -218,6 +218,7 @@ On process { variable font set em [* $scale 25.0] set x 0; set y 0 + set width 0 for {set i 0} {$i < [string length $text]} {incr i} { set char [string index $text $i] if {$char eq "\n"} { @@ -231,8 +232,9 @@ On process { } lassign $glyphInfo advance planeBounds atlasBounds set x [+ $x [* $advance $em]] + if {$x > $width} { set width $x } } - return [list $x $y] + return [list $width [+ $y $em]] } proc text {x0 y0 scale text radians} { variable font -- cgit v1.2.3 From b0c3e190aad5f948f041a9d3fd6929e2892dea17 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 29 Sep 2023 07:05:22 -0400 Subject: Use c struct for image_t Preparing to invent managed references --- virtual-programs/apriltags.folk | 22 +++++++++++----------- virtual-programs/images.folk | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 23 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/apriltags.folk b/virtual-programs/apriltags.folk index 69fcf51c..7e190a5b 100644 --- a/virtual-programs/apriltags.folk +++ b/virtual-programs/apriltags.folk @@ -53,17 +53,17 @@ On process { [list /someone/ wishes /something/ displays camera slice /slice/] proc subimage {im x y subwidth subheight} { - dict with im { - set x [expr {int($x)}] - set y [expr {int($y)}] - set subdata [expr {$data + ($y*$width + $x) * $components}] - dict create \ - width [int $subwidth] \ - height [int $subheight] \ - components $components \ - bytesPerRow $bytesPerRow \ - data [format 0x%x $subdata] - } + dict with im { + set x [expr {int($x)}] + set y [expr {int($y)}] + set subdata [expr {[lindex $data 1] + ($y*$width + $x) * $components}] + dict create \ + width [int $subwidth] \ + height [int $subheight] \ + components $components \ + bytesPerRow $bytesPerRow \ + data [format "(uint8_t*) 0x%x" $subdata] + } } set detector [AprilTags new $tagfamily] diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index 5523e0a0..bfa5daef 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -1,4 +1,3 @@ - # Example program, i.e the public API # # When $this has camera slice /slice/ { @@ -10,17 +9,17 @@ namespace eval ::image { proc width {im} { dict get $im width } proc height {im} { dict get $im height } proc subimage {im x y subwidth subheight} { - dict with im { - set x [expr {int($x)}] - set y [expr {int($y)}] - set subdata [expr {$data + ($y*$width + $x) * $components}] - dict create \ - width $subwidth \ - height $subheight \ - components $components \ - bytesPerRow $bytesPerRow \ - data [format 0x%x $subdata] - } + dict with im { + set x [expr {int($x)}] + set y [expr {int($y)}] + set subdata [expr {[lindex $data 1] + ($y*$width + $x) * $components}] + dict create \ + width $subwidth \ + height $subheight \ + components $components \ + bytesPerRow $bytesPerRow \ + data [format "(uint8_t*) 0x%x" $subdata] + } } set cc [c create] -- cgit v1.2.3 From 0514980d249fd72e23532c93c3615c1d52ce0c9d Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 30 Sep 2023 12:04:14 -0400 Subject: main,display: Version the Folk heap; evict stale/unused images. This at least keeps camera slices from crashing the system. TODO: Don't draw stale images. --- virtual-programs/display.folk | 55 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index e42ea621..222813a1 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -336,19 +336,56 @@ On process { return vec4(0.0, 0.0, 0.0, 0.0); }] variable imCache [dict create] - proc checkImCacheAndCopyIfNeeded {im} { + variable IMCACHE_MAX_IMAGES [- $Gpu::ImageManager::GPU_MAX_IMAGES 1] + proc checkImCacheAndCopyIfNeeded {imDrawSet} { variable imCache - if {![dict exists $imCache $im]} { - set gim [Gpu::ImageManager::copyImageToGpu $im] - dict set imCache $im $gim + variable IMCACHE_MAX_IMAGES + set notInCache [dictset difference $imDrawSet $imCache] + set notInDrawSet [dictset difference $imCache $imDrawSet] + + set numImagesToCopy [dictset size $notInCache] + if {$numImagesToCopy > 0} { + if {[dictset size $imCache] + $numImagesToCopy > $IMCACHE_MAX_IMAGES} { + set numImagesToEvict \ + [expr {[dictset size $imCache] + $numImagesToCopy - $IMCACHE_MAX_IMAGES}] + + # What can we safely evict? + # - Anything that's stale + # - Anything that's not in use + set numImagesEvicted 0 + dict for {im v} $imCache { + if {$numImagesEvicted == $numImagesToEvict} { break } + + lassign $v gim expectedVersion + set version [Heap::folkHeapGetVersion [string map {uint8_t void} [::image_t data_ptr $im]]] + if {$expectedVersion != $version} { + Gpu::ImageManager::freeGpuImage $gim + dict unset imCache $im + incr numImagesEvicted + continue + } + if {![dict exists $imDrawSet $im]} { + Gpu::ImageManager::freeGpuImage $gim + dict unset imCache $im + incr numImagesEvicted + } + } + } + + dict for {im _} $notInCache { + # TODO: This is unsafe (has a race condition) -- we're + # not locking the image, so version and gim may diverge. + set version [Heap::folkHeapGetVersion [string map {uint8_t void} [::image_t data_ptr $im]]] + set gim [Gpu::ImageManager::copyImageToGpu $im] + dict set imCache $im [list $gim $version] + } } } proc image {x y im radians {scale 1.0}} { # TODO: Implement scale. - # TODO: Free images from cache. variable image variable imCache - set gim [dict get $imCache $im] + lassign [dict get $imCache $im] gim Gpu::draw $image $gim [list [::image width $im] [::image height $im]] \ [list $x $y] $radians $scale } @@ -391,12 +428,16 @@ On process { } set displayCommands [lmap sublist [lsort -command lcomp $displayList] {lindex $sublist 1}] + + set imDrawSet [dictset create] foreach command $displayCommands { if {[lindex $command 0] eq "Display::image"} { set im [lindex $command 3] - Display::checkImCacheAndCopyIfNeeded $im + dictset add imDrawSet $im } } + Display::checkImCacheAndCopyIfNeeded $imDrawSet + set renderTime [baretime { Display::start foreach command $displayCommands { {*}$command } -- cgit v1.2.3 From b4fe442a55d200fc682a7ca4f202274458ec5f12 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Sat, 30 Sep 2023 12:12:48 -0400 Subject: display: Camera slice works! Always evict stale draw set images --- virtual-programs/display.folk | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 222813a1..f7b70959 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -340,6 +340,18 @@ On process { proc checkImCacheAndCopyIfNeeded {imDrawSet} { variable imCache variable IMCACHE_MAX_IMAGES + + dict for {im v} $imDrawSet { + if {![dict exists $imCache $im]} { continue } + # Check for staleness and remove from cache if so. + lassign [dict get $imCache $im] gim expectedVersion + set version [Heap::folkHeapGetVersion [string map {uint8_t void} [::image_t data_ptr $im]]] + if {$expectedVersion != $version} { + Gpu::ImageManager::freeGpuImage $gim + dict unset imCache $im + } + } + set notInCache [dictset difference $imDrawSet $imCache] set notInDrawSet [dictset difference $imCache $imDrawSet] -- cgit v1.2.3 From 82b53f173a6f08c5ee952eaa97def3cff61c92f1 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 2 Oct 2023 16:56:20 -0400 Subject: camera,calibrate: Fixing really bad breakage from refactors (mostly undoing refactor; also pointer fix in calibrate) --- virtual-programs/camera.folk | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/camera.folk b/virtual-programs/camera.folk index 8f49393d..0e1710e7 100644 --- a/virtual-programs/camera.folk +++ b/virtual-programs/camera.folk @@ -17,28 +17,13 @@ set height $::Camera::HEIGHT On process { source pi/Camera.tcl - set camera [Camera::cameraOpen "/dev/video0" $width $height] - Camera::cameraInit $camera - Camera::cameraStart $camera - # skip 5 frames for booting a cam - for {set i 0} {$i < 5} {incr i} { - Camera::cameraFrame $camera - } + Camera::init $width $height puts "Camera tid: [getTid] booted at [clock milliseconds]" - fn grayFrame {} { - if {![Camera::cameraFrame $camera]} { - error "Failed to capture from camera" - } - set image [Camera::newImage $width $height 1] - Camera::cameraDecompressGray $camera $image - return $image - } - set ::oldFrames [list] When $::thisProcess has step count /c/ { - set frame [grayFrame] + set frame [Camera::grayFrame] Commit { Claim the camera time is $::stepTime Claim the camera frame is $frame at [clock milliseconds] -- cgit v1.2.3 From 8dd6b9ff3321e539f5c7e8d118b1f0e2fd204d34 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Thu, 5 Oct 2023 23:31:03 +0000 Subject: Support other objects having programs --- virtual-programs/programs.folk | 22 ++++++++++++++++++++++ virtual-programs/tags-and-calibration.folk | 23 +---------------------- 2 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 virtual-programs/programs.folk (limited to 'virtual-programs') diff --git a/virtual-programs/programs.folk b/virtual-programs/programs.folk new file mode 100644 index 00000000..f42e1360 --- /dev/null +++ b/virtual-programs/programs.folk @@ -0,0 +1,22 @@ + + +When (non-capturing) /type/ /obj/ has a program { + puts "Added $type $obj" + On unmatch { puts "Removed $type $obj" } + + try { + set tempPath "$::env(HOME)/folk-printed-programs/$obj.folk.temp" + + if {[file exists $tempPath]} { + set path [open "$::env(HOME)/folk-printed-programs/$obj.folk.temp" r] + } else { + set path [open "$::env(HOME)/folk-printed-programs/$obj.folk" r] + } + set code [read $path] + close $path + + Claim $obj has program code $code + } on error error { + puts stderr "No code for $type $obj" + } +} diff --git a/virtual-programs/tags-and-calibration.folk b/virtual-programs/tags-and-calibration.folk index b219b541..9ad63a07 100644 --- a/virtual-programs/tags-and-calibration.folk +++ b/virtual-programs/tags-and-calibration.folk @@ -114,28 +114,6 @@ When camera /camera/ has width /cameraWidth/ height /cameraHeight/ { } } -When (non-capturing) tag /tag/ has center /c/ size /size/ { - Claim tag $tag is a tag -} - -When (non-capturing) tag /tag/ is a tag { - puts "Added tag $tag" - On unmatch { puts "Removed tag $tag" } - - set tempPath "$::env(HOME)/folk-printed-programs/$tag.folk.temp" - - if {[file exists $tempPath]} { - set path [open "$::env(HOME)/folk-printed-programs/$tag.folk.temp" r] - } else { - set path [open "$::env(HOME)/folk-printed-programs/$tag.folk" r] - } - set code [read $path] - close $path - - # Wish $tag is outlined green - Claim $tag has program code $code -} - When (non-capturing) tag /tag/ has corners /corners/ { set tagCorners [lmap p $corners {::cameraToProjector $p}] @@ -156,4 +134,5 @@ When (non-capturing) tag /tag/ has corners /corners/ { set region [region create $corners $edges $angle] Claim $tag has region $region + Claim tag $tag has a program } -- cgit v1.2.3 From 2dfdffd6753043cb8097f4c698e5c411ddc9855b Mon Sep 17 00:00:00 2001 From: Arcade Wise Date: Thu, 5 Oct 2023 21:11:31 -0400 Subject: Add changing fonts as an option to text rendering --- virtual-programs/display.folk | 33 ++++++++++++++++++++++++++++----- virtual-programs/label.folk | 9 +++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index f7b70959..daa819e9 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -112,7 +112,6 @@ On process { namespace export * namespace ensemble create } - variable font [font load "PTSans-Regular"] variable glyphMsd [Gpu::fn {sampler2D atlas vec4 atlasGlyphBounds vec2 glyphUv} vec4 { vec2 atlasUv = mix(atlasGlyphBounds.xw, atlasGlyphBounds.zy, glyphUv); return texture(atlas, vec2(atlasUv.x, 1.0-atlasUv.y)); @@ -214,8 +213,26 @@ On process { Gpu::draw $circle [list $x $y] $radius $thickness [getColor $color] [ne $filled "false"] } - proc textExtent {text scale} { - variable font + set ::FontCache [dict create] + + # load all fonts into the fontCache + foreach fontPath [list {*}[glob {*}vendor/fonts/*.png]] { + set fontName "" + regexp {vendor/fonts/(.*).png} $fontPath whole_match fontName + if {!($fontName eq "")} { + puts "Loaded $fontName into font cache" + set fontdata [font load $fontName] + dict set ::FontCache $fontName $fontdata + } + } + + proc textExtent {text scale {font "PTSans-Regular"}} { + if {!([dict exists $::FontCache $font])} { + throw {DISPLAY FONT {font doesn't exist}} "$font doesn't exist" + return + } + set font [dict get $::FontCache $font] + set em [* $scale 25.0] set x 0; set y 0 set width 0 @@ -236,8 +253,14 @@ On process { } return [list $width [+ $y $em]] } - proc text {x0 y0 scale text radians} { - variable font + proc text {x0 y0 scale text radians {font ""}} { + if {!([dict exists $::FontCache $font])} { + throw {DISPLAY FONT {font doesn't exist}} "$font doesn't exist" + return + } + set font [dict get $::FontCache $font] + + variable glyph set fontAtlas [font gpuAtlasImage $font] set fontAtlasSize [list [::image width [font atlasImage $font]] \ diff --git a/virtual-programs/label.folk b/virtual-programs/label.folk index ad5e406f..18c6e139 100644 --- a/virtual-programs/label.folk +++ b/virtual-programs/label.folk @@ -4,15 +4,20 @@ When /thing/ has region /region/ { # set height [region height $region] set radians [region angle $region] - When the collected matches for [list /someone/ wishes $thing is labelled /text/] are /matches/ { + When the collected matches for [list /someone/ wishes $thing is labelled /text/ with font /font/] are /matches/ { set text [join [lmap match $matches {dict get $match text}] "\n"] if {$text eq ""} { return } set scale 1 - Display::text $x $y $scale $text $radians + Display::text $x $y $scale $text $radians [dict get $match font] } } +When /someone/ wishes /thing/ is labelled /text/ { + # Set the default font + Wish $thing is labelled $text with font "PTSans-Regular" +} + fn text {coords text angle} { Display::text [lindex $coords 0] [lindex $coords 1] 2 $text $angle } -- cgit v1.2.3 From 35e329acac3246006345ce6efeedc3d7710215cc Mon Sep 17 00:00:00 2001 From: Arcade Wise Date: Thu, 5 Oct 2023 21:13:40 -0400 Subject: oops, forgot to add to the 2nd function --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index daa819e9..4bce8a00 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -253,7 +253,7 @@ On process { } return [list $width [+ $y $em]] } - proc text {x0 y0 scale text radians {font ""}} { + proc text {x0 y0 scale text radians {font "PTSans-Regular"}} { if {!([dict exists $::FontCache $font])} { throw {DISPLAY FONT {font doesn't exist}} "$font doesn't exist" return -- cgit v1.2.3 From cc5864480e41322e384d702df0d6814348a25467 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 5 Oct 2023 21:42:27 -0400 Subject: display: Catch errors, so we don't hard crash if font doesn't exist --- virtual-programs/display.folk | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 4bce8a00..d7c0f2b1 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -475,7 +475,10 @@ On process { set renderTime [baretime { Display::start - foreach command $displayCommands { {*}$command } + foreach command $displayCommands { + try { {*}$command } \ + on error e { puts stderr $::errorInfo } + } Display::end }] -- cgit v1.2.3 From 5a662a3df4e4a64210065fe3601fe87e63053bce Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Thu, 5 Oct 2023 21:44:40 -0400 Subject: display: Make image cache shrink when more fonts are loaded --- virtual-programs/display.folk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index d7c0f2b1..f92afb67 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -359,7 +359,7 @@ On process { return vec4(0.0, 0.0, 0.0, 0.0); }] variable imCache [dict create] - variable IMCACHE_MAX_IMAGES [- $Gpu::ImageManager::GPU_MAX_IMAGES 1] + variable IMCACHE_MAX_IMAGES [- $Gpu::ImageManager::GPU_MAX_IMAGES [dict size $::FontCache]] proc checkImCacheAndCopyIfNeeded {imDrawSet} { variable imCache variable IMCACHE_MAX_IMAGES -- cgit v1.2.3 From 58111948f9656591852f3e38b09630cf4b8a38df Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Fri, 6 Oct 2023 12:09:05 -0400 Subject: images: Fix saving images with stride --- virtual-programs/images.folk | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/images.folk b/virtual-programs/images.folk index bfa5daef..e748cd11 100644 --- a/virtual-programs/images.folk +++ b/virtual-programs/images.folk @@ -48,7 +48,7 @@ namespace eval ::image { #include void - jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t width, uint32_t height, int quality) + jpeg(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height, int quality) { JSAMPARRAY image; if (components == 1) { @@ -56,9 +56,9 @@ namespace eval ::image { for (size_t i = 0; i < height; i++) { image[i] = calloc(width * 3, sizeof (JSAMPLE)); for (size_t j = 0; j < width; j++) { - image[i][j * 3 + 0] = data[(i * width + j)]; - image[i][j * 3 + 1] = data[(i * width + j)]; - image[i][j * 3 + 2] = data[(i * width + j)]; + image[i][j * 3 + 0] = data[(i*bytesPerRow + j)]; + image[i][j * 3 + 1] = data[(i*bytesPerRow + j)]; + image[i][j * 3 + 2] = data[(i*bytesPerRow + j)]; } } } else if (components == 3) { @@ -66,9 +66,9 @@ namespace eval ::image { for (size_t i = 0; i < height; i++) { image[i] = calloc(width * 3, sizeof (JSAMPLE)); for (size_t j = 0; j < width; j++) { - image[i][j * 3 + 0] = data[(i * width + j) * 3]; - image[i][j * 3 + 1] = data[(i * width + j) * 3 + 1]; - image[i][j * 3 + 2] = data[(i * width + j) * 3 + 2]; + image[i][j * 3 + 0] = data[i*bytesPerRow + j*3]; + image[i][j * 3 + 1] = data[i*bytesPerRow + j*3 + 1]; + image[i][j * 3 + 2] = data[i*bytesPerRow + j*3 + 2]; } } } else { exit(1); } @@ -96,7 +96,7 @@ namespace eval ::image { free(image); } - void png(FILE* dest, uint8_t* data, uint32_t components, uint32_t width, uint32_t height) { + void png(FILE* dest, uint8_t* data, uint32_t components, uint32_t bytesPerRow, uint32_t width, uint32_t height) { png_structp png_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_infop info_w = png_create_info_struct(png_w); @@ -104,14 +104,15 @@ namespace eval ::image { png_set_IHDR(png_w, info_w, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - else + else if (components == 1) png_set_IHDR(png_w, info_w, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + else exit(1); png_bytep* row_pointers = (png_bytep *)malloc(sizeof(png_bytep) * height); for (int i = 0; i < height; i++) { - row_pointers[i] = data + i * width * components; + row_pointers[i] = data + i * bytesPerRow; } png_init_io(png_w, dest); @@ -124,12 +125,12 @@ namespace eval ::image { } $cc proc saveAsJpeg {image_t im char* filename} void { FILE* out = fopen(filename, "w"); - jpeg(out, im.data, im.components, im.width, im.height, 100); + jpeg(out, im.data, im.components, im.bytesPerRow, im.width, im.height, 100); fclose(out); } $cc proc saveAsPng {image_t im char* filename} void { FILE* out = fopen(filename, "wb"); - png(out, im.data, im.components, im.width, im.height); + png(out, im.data, im.components, im.bytesPerRow, im.width, im.height); fclose(out); } # Given the four corners of a region in an image, warp it to a new image of a given width and height -- cgit v1.2.3 From b8bffe3cf3596239a569284043174164d2785475 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Sat, 7 Oct 2023 01:10:18 +0000 Subject: Implement arc primitive The arc is specified as start angle (from positive x axis) plus arc length (both in the range [0, 2*pi)) --- virtual-programs/display.folk | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index f92afb67..546e1861 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -190,6 +190,38 @@ On process { } } + variable arc [Gpu::pipeline {vec2 center float start float arclen float radius float thickness vec4 color int filled} { + float r = radius + thickness; + vec2 vertices[4] = vec2[4]( + center - r, + vec2(center.x + r, center.y - r), + vec2(center.x - r, center.y + r), + center + r + ); + return vertices[gl_VertexIndex]; + } { + #define M_TWO_PI 6.283185307179586 + start = clamp(start, 0, M_TWO_PI); + arclen = clamp(arclen, 0, M_TWO_PI); + + float dist = length(gl_FragCoord.xy - center) - radius; + float angle = atan(-(gl_FragCoord.y - center.y), gl_FragCoord.x - center.x); + + // Shift angle from [-pi, pi) to [0, 2*pi] + angle = (angle < 0) ? (angle + M_TWO_PI) : angle; + float end = start + arclen; + + return ((dist < thickness && dist > 0.0) && + ((end < M_TWO_PI && angle > start && angle < end) || + (end >= M_TWO_PI && (angle > start || angle < end-M_TWO_PI)))) ? color : vec4(0, 0, 0, 0); + + }] + + proc arc {x y start arclen radius thickness color {filled false}} { + variable arc + Gpu::draw $arc [list $x $y] $start $arclen $radius $thickness [getColor $color] [ne $filled "false"] + } + # TODO: Fix bool support. variable circle [Gpu::pipeline {vec2 center float radius float thickness vec4 color int filled} { float r = radius + thickness; -- cgit v1.2.3 From b2b4768a73458ca214198c9d9e751aceb036ef80 Mon Sep 17 00:00:00 2001 From: Naveen Michaud-Agrawal Date: Sat, 7 Oct 2023 21:49:11 +0000 Subject: Add claim for display size --- virtual-programs/display.folk | 2 ++ 1 file changed, 2 insertions(+) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index f92afb67..36a370e7 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -23,6 +23,8 @@ namespace eval ::Display { uplevel [list Wish display runs [list $func {*}$args] on layer $::Display::LAYER] } } + + Claim the display Display has width $::Display::WIDTH height $::Display::HEIGHT } On process { -- cgit v1.2.3 From f77cbd902cf1d352661261cd0fbf53d2b6bc1dba Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 9 Oct 2023 13:36:11 -0400 Subject: display: Remove filled arg from arc --- virtual-programs/display.folk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'virtual-programs') diff --git a/virtual-programs/display.folk b/virtual-programs/display.folk index 546e1861..bae5951f 100644 --- a/virtual-programs/display.folk +++ b/virtual-programs/display.folk @@ -190,7 +190,7 @@ On process { } } - variable arc [Gpu::pipeline {vec2 center float start float arclen float radius float thickness vec4 color int filled} { + variable arc [Gpu::pipeline {vec2 center float start float arclen float radius float thickness vec4 color} { float r = radius + thickness; vec2 vertices[4] = vec2[4]( center - r, @@ -217,9 +217,9 @@ On process { }] - proc arc {x y start arclen radius thickness color {filled false}} { + proc arc {x y start arclen radius thickness color} { variable arc - Gpu::draw $arc [list $x $y] $start $arclen $radius $thickness [getColor $color] [ne $filled "false"] + Gpu::draw $arc [list $x $y] $start $arclen $radius $thickness [getColor $color] } # TODO: Fix bool support. -- cgit v1.2.3